Cleanup CommentCreate

This commit is contained in:
Rafael 2022-02-07 15:03:10 -03:00 committed by Thomas Zarebczan
parent 67053beda9
commit 2b56ca8599
4 changed files with 124 additions and 113 deletions

26
flow-typed/Comment.js vendored
View file

@ -21,6 +21,16 @@ declare type Comment = {
removed?: boolean, removed?: boolean,
}; };
declare type CommentSubmitParams = {
comment: string,
claim_id: string,
parent_id?: string,
txid?: ?string,
payment_intent_id?: ?string,
environment?: ?string,
sticker: boolean,
};
declare type PerChannelSettings = { declare type PerChannelSettings = {
words?: Array<string>, words?: Array<string>,
comments_enabled?: boolean, comments_enabled?: boolean,
@ -156,13 +166,13 @@ declare type CommentListResponse = {
declare type CommentByIdParams = { declare type CommentByIdParams = {
comment_id: string, comment_id: string,
with_ancestors: boolean, with_ancestors: boolean,
} };
declare type CommentByIdResponse = { declare type CommentByIdResponse = {
item: Comment, item: Comment,
items: Comment, items: Comment,
ancestors: Array<Comment>, ancestors: Array<Comment>,
} };
declare type CommentPinParams = { declare type CommentPinParams = {
comment_id: string, comment_id: string,
@ -171,20 +181,20 @@ declare type CommentPinParams = {
remove?: boolean, remove?: boolean,
signature: string, signature: string,
signing_ts: string, signing_ts: string,
} };
declare type CommentPinResponse = { declare type CommentPinResponse = {
items: Comment, // "items" is an inherited typo to match SDK. Will be "item" in a new version. items: Comment, // "items" is an inherited typo to match SDK. Will be "item" in a new version.
} };
declare type CommentEditParams = { declare type CommentEditParams = {
comment: string, comment: string,
comment_id: string, comment_id: string,
signature: string, signature: string,
signing_ts: string, signing_ts: string,
} };
declare type CommentEditResponse = Comment declare type CommentEditResponse = Comment;
declare type CommentAbandonParams = { declare type CommentAbandonParams = {
comment_id: string, comment_id: string,
@ -279,7 +289,7 @@ declare type ModerationAmIParams = {
channel_name: string, channel_name: string,
channel_id: string, channel_id: string,
signature: string, signature: string,
signing_ts: string signing_ts: string,
}; };
declare type SettingsParams = { declare type SettingsParams = {
@ -308,7 +318,7 @@ declare type UpdateSettingsParams = {
min_tip_amount_comment?: number, min_tip_amount_comment?: number,
min_tip_amount_super_chat?: number, min_tip_amount_super_chat?: number,
slow_mode_min_gap?: number, slow_mode_min_gap?: number,
} };
declare type BlockWordParams = { declare type BlockWordParams = {
channel_name: string, channel_name: string,

View file

@ -13,43 +13,46 @@ import { doSendTip, doSendCashTip } from 'redux/actions/wallet';
import { doToast } from 'redux/actions/notifications'; import { doToast } from 'redux/actions/notifications';
import { selectActiveChannelClaim } from 'redux/selectors/app'; import { selectActiveChannelClaim } from 'redux/selectors/app';
import { selectSettingsByChannelId } from 'redux/selectors/comments'; import { selectSettingsByChannelId } from 'redux/selectors/comments';
import { getChannelIdFromClaim } from 'util/claim';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
const select = (state, props) => { const select = (state, props) => {
const claim = selectClaimForUri(state, props.uri); const { uri } = props;
const claim = selectClaimForUri(state, uri);
const { claim_id: claimId, name, signing_channel: channel } = claim || {};
// setup variables for tip API
const channelClaimId = getChannelIdFromClaim(claim);
const tipChannelName = channel ? channel.name : name;
const activeChannelClaim = selectActiveChannelClaim(state);
const { claim_id: activeChannelClaimId, name: activeChannelName, canonical_url: activeChannelUrl } =
activeChannelClaim || {};
return { return {
activeChannelClaim: selectActiveChannelClaim(state), activeChannelClaimId,
activeChannelName,
activeChannelUrl,
hasChannels: selectHasChannels(state), hasChannels: selectHasChannels(state),
claim, claimId,
channelClaimId,
tipChannelName,
claimIsMine: selectClaimIsMine(state, claim), claimIsMine: selectClaimIsMine(state, claim),
isFetchingChannels: selectFetchingMyChannels(state), isFetchingChannels: selectFetchingMyChannels(state),
settingsByChannelId: selectSettingsByChannelId(state), settingsByChannelId: selectSettingsByChannelId(state),
supportDisabled: makeSelectTagInClaimOrChannelForUri(props.uri, DISABLE_SUPPORT_TAG)(state), supportDisabled: makeSelectTagInClaimOrChannelForUri(uri, DISABLE_SUPPORT_TAG)(state),
}; };
}; };
const perform = (dispatch, ownProps) => ({ const perform = {
createComment: (comment, claimId, parentId, txid, payment_intent_id, environment, sticker) => doCommentCreate,
dispatch( doFetchCreatorSettings,
doCommentCreate( doToast,
comment, doCommentById,
claimId, doSendCashTip,
parentId, doSendTip,
ownProps.uri, doOpenModal,
ownProps.isLivestream, };
txid,
payment_intent_id,
environment,
sticker
)
),
doFetchCreatorSettings: (channelClaimId) => dispatch(doFetchCreatorSettings(channelClaimId)),
doToast: (options) => dispatch(doToast(options)),
fetchComment: (commentId) => dispatch(doCommentById(commentId, false)),
sendCashTip: (tipParams, userParams, claimId, environment, successCallback) =>
dispatch(doSendCashTip(tipParams, false, userParams, claimId, environment, successCallback)),
sendTip: (params, callback, errorCallback) => dispatch(doSendTip(params, false, callback, errorCallback, false)),
doOpenModal: (id, params) => dispatch(doOpenModal(id, params)),
});
export default connect(select, perform)(CommentCreate); export default connect(select, perform)(CommentCreate);

View file

@ -5,7 +5,6 @@ import 'scss/component/_comment-create.scss';
import { buildValidSticker } from 'util/comments'; import { buildValidSticker } from 'util/comments';
import { FF_MAX_CHARS_IN_COMMENT, FF_MAX_CHARS_IN_LIVESTREAM_COMMENT } from 'constants/form-field'; import { FF_MAX_CHARS_IN_COMMENT, FF_MAX_CHARS_IN_LIVESTREAM_COMMENT } from 'constants/form-field';
import { FormField, Form } from 'component/common/form'; import { FormField, Form } from 'component/common/form';
import { getChannelIdFromClaim } from 'util/claim';
import { Lbryio } from 'lbryinc'; import { Lbryio } from 'lbryinc';
import { SIMPLE_SITE } from 'config'; import { SIMPLE_SITE } from 'config';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
@ -36,10 +35,14 @@ type UserParams = { activeChannelName: ?string, activeChannelId: ?string };
type Props = { type Props = {
activeChannel: string, activeChannel: string,
activeChannelClaim: ?ChannelClaim, activeChannelClaimId?: string,
activeChannelName?: string,
activeChannelUrl?: string,
bottom: boolean, bottom: boolean,
hasChannels: boolean, hasChannels: boolean,
claim: StreamClaim, claimId?: string,
channelClaimId?: string,
tipChannelName?: string,
claimIsMine: boolean, claimIsMine: boolean,
embed?: boolean, embed?: boolean,
isFetchingChannels: boolean, isFetchingChannels: boolean,
@ -52,25 +55,29 @@ type Props = {
supportDisabled: boolean, supportDisabled: boolean,
uri: string, uri: string,
disableInput?: boolean, disableInput?: boolean,
createComment: (string, string, string, ?string, ?string, ?string, boolean) => Promise<any>, setQuickReply: (any) => void,
doFetchCreatorSettings: (channelId: string) => Promise<any>,
doToast: ({ message: string }) => void,
fetchComment: (commentId: string) => Promise<any>,
onCancelReplying?: () => void, onCancelReplying?: () => void,
onDoneReplying?: () => void, onDoneReplying?: () => void,
sendCashTip: (TipParams, UserParams, string, ?string, (any) => void) => string, // redux
sendTip: ({}, (any) => void, (any) => void) => void, doCommentCreate: (uri: string, isLivestream?: boolean, params: CommentSubmitParams) => Promise<any>,
setQuickReply: (any) => void, doFetchCreatorSettings: (channelId: string) => Promise<any>,
toast: (string) => void, doToast: ({ message: string }) => void,
doCommentById: (commentId: string) => Promise<any>,
doSendCashTip: (TipParams, UserParams, string, ?string, (any) => void) => string,
doSendTip: ({}, (any) => void, (any) => void) => void,
doOpenModal: (id: string, any) => void, doOpenModal: (id: string, any) => void,
}; };
export function CommentCreate(props: Props) { export function CommentCreate(props: Props) {
const { const {
activeChannelClaim, activeChannelClaimId,
activeChannelName,
activeChannelUrl,
bottom, bottom,
hasChannels, hasChannels,
claim, claimId,
channelClaimId,
tipChannelName,
claimIsMine, claimIsMine,
embed, embed,
isFetchingChannels, isFetchingChannels,
@ -83,14 +90,14 @@ export function CommentCreate(props: Props) {
supportDisabled, supportDisabled,
uri, uri,
disableInput, disableInput,
createComment, doCommentCreate,
doFetchCreatorSettings, doFetchCreatorSettings,
doToast, doToast,
fetchComment, doCommentById,
onCancelReplying, onCancelReplying,
onDoneReplying, onDoneReplying,
sendCashTip, doSendCashTip,
sendTip, doSendTip,
setQuickReply, setQuickReply,
doOpenModal, doOpenModal,
} = props; } = props;
@ -125,12 +132,10 @@ export function CommentCreate(props: Props) {
const [canReceiveFiatTip, setCanReceiveFiatTip] = React.useState(undefined); const [canReceiveFiatTip, setCanReceiveFiatTip] = React.useState(undefined);
const [tipModalOpen, setTipModalOpen] = React.useState(undefined); const [tipModalOpen, setTipModalOpen] = React.useState(undefined);
const claimId = claim && claim.claim_id;
const charCount = commentValue ? commentValue.length : 0; const charCount = commentValue ? commentValue.length : 0;
const hasNothingToSumbit = !commentValue.length && !selectedSticker; const hasNothingToSumbit = !commentValue.length && !selectedSticker;
const disabled = deletedComment || isSubmitting || isFetchingChannels || hasNothingToSumbit || disableInput; const disabled = deletedComment || isSubmitting || isFetchingChannels || hasNothingToSumbit || disableInput;
const channelId = getChannelIdFromClaim(claim); const channelSettings = channelClaimId ? settingsByChannelId[channelClaimId] : undefined;
const channelSettings = channelId ? settingsByChannelId[channelId] : undefined;
const minSuper = (channelSettings && channelSettings.min_tip_amount_super_chat) || 0; const minSuper = (channelSettings && channelSettings.min_tip_amount_super_chat) || 0;
const minTip = (channelSettings && channelSettings.min_tip_amount_comment) || 0; const minTip = (channelSettings && channelSettings.min_tip_amount_comment) || 0;
const minAmount = minTip || minSuper || 0; const minAmount = minTip || minSuper || 0;
@ -210,9 +215,9 @@ export function CommentCreate(props: Props) {
} }
function handleSupportComment() { function handleSupportComment() {
if (!activeChannelClaim) return; if (!activeChannelClaimId) return;
if (!channelId) { if (!channelClaimId) {
doToast({ doToast({
message: __('Unable to verify channel settings. Try refreshing the page.'), message: __('Unable to verify channel settings. Try refreshing the page.'),
isError: true, isError: true,
@ -229,7 +234,7 @@ export function CommentCreate(props: Props) {
} }
// !! Beware of stale closure when editing the then-block, including doSubmitTip(). // !! Beware of stale closure when editing the then-block, including doSubmitTip().
doFetchCreatorSettings(channelId).then(() => { doFetchCreatorSettings(channelClaimId).then(() => {
const lockedMinAmount = minAmount; // value during closure. const lockedMinAmount = minAmount; // value during closure.
const currentMinAmount = minAmountRef.current; // value from latest doFetchCreatorSettings(). const currentMinAmount = minAmountRef.current; // value from latest doFetchCreatorSettings().
@ -247,22 +252,18 @@ export function CommentCreate(props: Props) {
} }
function doSubmitTip() { function doSubmitTip() {
if (!activeChannelClaim || isSubmitting) return; if (!claimId || !channelClaimId || !activeChannelName || !activeChannelClaimId || isSubmitting || !tipChannelName) {
return;
}
setSubmitting(true); setSubmitting(true);
const params = { amount: tipAmount, claim_id: claimId, channel_id: activeChannelClaim.claim_id }; const params = { amount: tipAmount, claim_id: claimId, channel_id: activeChannelClaimId };
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) { if (activeTab === TAB_LBC) {
// call sendTip and then run the callback from the response // call doSendTip and then run the callback from the response
// second parameter is callback // second parameter is callback
sendTip( doSendTip(
params, params,
(response) => { (response) => {
const { txid } = response; const { txid } = response;
@ -287,9 +288,9 @@ export function CommentCreate(props: Props) {
); );
} else { } else {
const tipParams: TipParams = { tipAmount: Math.round(tipAmount * 100) / 100, tipChannelName, channelClaimId }; const tipParams: TipParams = { tipAmount: Math.round(tipAmount * 100) / 100, tipChannelName, channelClaimId };
const userParams: UserParams = { activeChannelName, activeChannelId }; const userParams: UserParams = { activeChannelName, activeChannelId: activeChannelClaimId };
sendCashTip(tipParams, userParams, claim.claim_id, stripeEnvironment, (customerTipResponse) => { doSendCashTip(tipParams, userParams, claimId, stripeEnvironment, (customerTipResponse) => {
const { payment_intent_id } = customerTipResponse; const { payment_intent_id } = customerTipResponse;
handleCreateComment(null, payment_intent_id, stripeEnvironment); handleCreateComment(null, payment_intent_id, stripeEnvironment);
@ -310,13 +311,21 @@ export function CommentCreate(props: Props) {
* @param {string} [environment] Optional environment for Stripe (test|live) * @param {string} [environment] Optional environment for Stripe (test|live)
*/ */
function handleCreateComment(txid, payment_intent_id, environment) { function handleCreateComment(txid, payment_intent_id, environment) {
if (isSubmitting || disableInput) return; if (isSubmitting || disableInput || !claimId) return;
setSubmitting(true); setSubmitting(true);
const stickerValue = selectedSticker && buildValidSticker(selectedSticker.name); const stickerValue = selectedSticker && buildValidSticker(selectedSticker.name);
createComment(stickerValue || commentValue, claimId, parentId, txid, payment_intent_id, environment, !!stickerValue) doCommentCreate(uri, isLivestream, {
comment: stickerValue || commentValue,
claim_id: claimId,
parent_id: parentId,
txid,
payment_intent_id,
environment,
sticker: !!stickerValue,
})
.then((res) => { .then((res) => {
setSubmitting(false); setSubmitting(false);
if (setQuickReply) setQuickReply(res); if (setQuickReply) setQuickReply(res);
@ -336,10 +345,10 @@ export function CommentCreate(props: Props) {
setSubmitting(false); setSubmitting(false);
setCommentFailure(true); setCommentFailure(true);
if (channelId) { if (channelClaimId) {
// It could be that the creator added a minimum tip setting. // It could be that the creator added a minimum tip setting.
// Manually update for now until a websocket msg is available. // Manually update for now until a websocket msg is available.
doFetchCreatorSettings(channelId); doFetchCreatorSettings(channelClaimId);
} }
}); });
} }
@ -363,19 +372,19 @@ export function CommentCreate(props: Props) {
// Fetch channel constraints if not already. // Fetch channel constraints if not already.
React.useEffect(() => { React.useEffect(() => {
if (!channelSettings && channelId) { if (!channelSettings && channelClaimId) {
doFetchCreatorSettings(channelId); doFetchCreatorSettings(channelClaimId);
} }
}, []); // eslint-disable-line react-hooks/exhaustive-deps }, []); // eslint-disable-line react-hooks/exhaustive-deps
// Notifications: Fetch top-level comments to identify if it has been deleted and can reply to it // Notifications: Fetch top-level comments to identify if it has been deleted and can reply to it
React.useEffect(() => { React.useEffect(() => {
if (shouldFetchComment && fetchComment) { if (shouldFetchComment && doCommentById) {
fetchComment(parentId).then((result) => { doCommentById(parentId).then((result) => {
setDeletedComment(String(result).includes('Error')); setDeletedComment(String(result).includes('Error'));
}); });
} }
}, [fetchComment, shouldFetchComment, parentId]); }, [doCommentById, shouldFetchComment, parentId]);
// Stickers: Get LBC-USD exchange rate if hasn't yet and selected a paid sticker // Stickers: Get LBC-USD exchange rate if hasn't yet and selected a paid sticker
React.useEffect(() => { React.useEffect(() => {
@ -385,10 +394,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, // 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) // it defaults to LBC tip instead of USD)
React.useEffect(() => { React.useEffect(() => {
if (!stripeEnvironment || !showSelectors || canReceiveFiatTip !== undefined) return; if (!stripeEnvironment || !showSelectors || canReceiveFiatTip !== undefined || !tipChannelName) 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( Lbryio.call(
'account', 'account',
@ -408,7 +414,7 @@ export function CommentCreate(props: Props) {
} }
}) })
.catch(() => {}); .catch(() => {});
}, [canReceiveFiatTip, claim.claim_id, claim.name, claim.signing_channel, showSelectors]); }, [canReceiveFiatTip, channelClaimId, showSelectors, tipChannelName]);
// Handle keyboard shortcut comment creation // Handle keyboard shortcut comment creation
React.useEffect(() => { React.useEffect(() => {
@ -502,19 +508,19 @@ export function CommentCreate(props: Props) {
})} })}
> >
{selectedSticker ? ( {selectedSticker ? (
activeChannelClaim && ( activeChannelUrl && (
<StickerReviewBox <StickerReviewBox
activeChannelUrl={activeChannelClaim.canonical_url} activeChannelUrl={activeChannelUrl}
src={selectedSticker.url} src={selectedSticker.url}
price={selectedSticker.price || 0} price={selectedSticker.price || 0}
exchangeRate={exchangeRate} exchangeRate={exchangeRate}
/> />
) )
) : isReviewingSupportComment ? ( ) : isReviewingSupportComment ? (
activeChannelClaim && activeChannelUrl &&
activeTab && ( activeTab && (
<TipReviewBox <TipReviewBox
activeChannelUrl={activeChannelClaim.canonical_url} activeChannelUrl={activeChannelUrl}
tipAmount={tipAmount} tipAmount={tipAmount}
activeTab={activeTab} activeTab={activeTab}
message={commentValue} message={commentValue}

View file

@ -470,18 +470,10 @@ export function doCommentReact(commentId: string, type: string) {
* @param {string} [environment] Optional environment for Stripe (test|live) * @param {string} [environment] Optional environment for Stripe (test|live)
* @returns {(function(Dispatch, GetState): Promise<undefined|void|*>)|*} * @returns {(function(Dispatch, GetState): Promise<undefined|void|*>)|*}
*/ */
export function doCommentCreate( export function doCommentCreate(uri: string, livestream: boolean, params: CommentSubmitParams) {
comment: string = '',
claim_id: string = '',
parent_id?: string,
uri: string,
livestream?: boolean = false,
txid?: string,
payment_intent_id?: string,
environment?: string,
sticker: boolean
) {
return async (dispatch: Dispatch, getState: GetState) => { return async (dispatch: Dispatch, getState: GetState) => {
const { comment, claim_id, parent_id, txid, payment_intent_id, environment, sticker } = params;
const state = getState(); const state = getState();
const activeChannelClaim = selectActiveChannelClaim(state); const activeChannelClaim = selectActiveChannelClaim(state);
const mentionedChannels: Array<MentionedChannel> = []; const mentionedChannels: Array<MentionedChannel> = [];