Refactor fileActions

- moved doPrepareEdit incognito and channel calls to separate action
- same with download
- Tooltips
- No major differences between mobile or default returned components so removed condition since mobile style will be changed later on this branch
This commit is contained in:
Rafael 2022-02-01 17:11:35 -03:00 committed by Thomas Zarebczan
parent 1fb154f7fe
commit 5794432288
6 changed files with 133 additions and 153 deletions

View file

@ -1,7 +1,7 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectClaimForUri, selectClaimIsMine } from 'redux/selectors/claims'; import { selectClaimForUri, selectClaimIsMine } from 'redux/selectors/claims';
import { doCollectionEdit, doFetchItemsInCollection } from 'redux/actions/collections'; import { doCollectionEdit, doFetchItemsInCollection } from 'redux/actions/collections';
import { doPrepareEdit } from 'redux/actions/publish'; import { doEditForChannel } from 'redux/actions/publish';
import { import {
makeSelectCollectionForIdHasClaimUrl, makeSelectCollectionForIdHasClaimUrl,
makeSelectCollectionIsMine, makeSelectCollectionIsMine,
@ -12,7 +12,7 @@ import { makeSelectFileInfoForUri } from 'redux/selectors/file_info';
import * as COLLECTIONS_CONSTS from 'constants/collections'; import * as COLLECTIONS_CONSTS from 'constants/collections';
import { makeSelectChannelIsMuted } from 'redux/selectors/blocked'; import { makeSelectChannelIsMuted } from 'redux/selectors/blocked';
import { doChannelMute, doChannelUnmute } from 'redux/actions/blocked'; import { doChannelMute, doChannelUnmute } from 'redux/actions/blocked';
import { doSetActiveChannel, doSetIncognito, doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import { import {
doCommentModBlock, doCommentModBlock,
doCommentModUnBlock, doCommentModUnBlock,
@ -76,16 +76,7 @@ const select = (state, props) => {
}; };
const perform = (dispatch) => ({ const perform = (dispatch) => ({
prepareEdit: (publishData, uri, fileInfo) => { prepareEdit: (publishData, uri, fileInfo) => doEditForChannel(publishData, uri, fileInfo, fs),
if (publishData.signing_channel) {
dispatch(doSetIncognito(false));
dispatch(doSetActiveChannel(publishData.signing_channel.claim_id));
} else {
dispatch(doSetIncognito(true));
}
dispatch(doPrepareEdit(publishData, uri, fileInfo, fs));
},
doToast: (props) => dispatch(doToast(props)), doToast: (props) => dispatch(doToast(props)),
openModal: (modal, props) => dispatch(doOpenModal(modal, props)), openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
doChannelMute: (channelUri) => dispatch(doChannelMute(channelUri)), doChannelMute: (channelUri) => dispatch(doChannelMute(channelUri)),

View file

@ -6,48 +6,39 @@ import {
selectIsStreamPlaceholderForUri, selectIsStreamPlaceholderForUri,
makeSelectTagInClaimOrChannelForUri, makeSelectTagInClaimOrChannelForUri,
} from 'redux/selectors/claims'; } from 'redux/selectors/claims';
import { makeSelectStreamingUrlForUri, makeSelectFileInfoForUri } from 'redux/selectors/file_info'; import { makeSelectStreamingUrlForUri } from 'redux/selectors/file_info';
import { doPrepareEdit } from 'redux/actions/publish'; import { doEditForChannel } from 'redux/actions/publish';
import { selectCostInfoForUri } from 'lbryinc'; import { selectCostInfoForUri } from 'lbryinc';
import { doSetPlayingUri, doPlayUri } from 'redux/actions/content'; import { doClearPlayingUri, doDownloadUri } from 'redux/actions/content';
import { doToast } from 'redux/actions/notifications'; import { doToast } from 'redux/actions/notifications';
import { doOpenModal, doSetActiveChannel, doSetIncognito, doAnalyticsView } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import fs from 'fs';
import FileActions from './view'; import FileActions from './view';
import { makeSelectFileRenderModeForUri } from 'redux/selectors/content'; import { makeSelectFileRenderModeForUri } from 'redux/selectors/content';
import { DISABLE_DOWNLOAD_BUTTON_TAG } from 'constants/tags'; import { DISABLE_DOWNLOAD_BUTTON_TAG } from 'constants/tags';
const select = (state, props) => { const select = (state, props) => {
const claim = selectClaimForUri(state, props.uri); const { uri } = props;
const claim = selectClaimForUri(state, uri);
return { return {
claim, claim,
claimIsMine: selectClaimIsMine(state, claim), claimIsMine: selectClaimIsMine(state, claim),
fileInfo: makeSelectFileInfoForUri(props.uri)(state), renderMode: makeSelectFileRenderModeForUri(uri)(state),
renderMode: makeSelectFileRenderModeForUri(props.uri)(state), costInfo: selectCostInfoForUri(state, uri),
costInfo: selectCostInfoForUri(state, props.uri),
hasChannels: selectHasChannels(state), hasChannels: selectHasChannels(state),
isLivestreamClaim: selectIsStreamPlaceholderForUri(state, props.uri), isLivestreamClaim: selectIsStreamPlaceholderForUri(state, uri),
streamingUrl: makeSelectStreamingUrlForUri(props.uri)(state), streamingUrl: makeSelectStreamingUrlForUri(uri)(state),
disableDownloadButton: makeSelectTagInClaimOrChannelForUri(props.uri, DISABLE_DOWNLOAD_BUTTON_TAG)(state), disableDownloadButton: makeSelectTagInClaimOrChannelForUri(props.uri, DISABLE_DOWNLOAD_BUTTON_TAG)(state),
}; };
}; };
const perform = (dispatch) => ({ const perform = {
openModal: (modal, props) => dispatch(doOpenModal(modal, props)), doOpenModal,
prepareEdit: (publishData, uri, fileInfo) => { doEditForChannel,
if (publishData.signing_channel) { doClearPlayingUri,
dispatch(doSetIncognito(false)); doToast,
dispatch(doSetActiveChannel(publishData.signing_channel.claim_id)); doDownloadUri,
} else { };
dispatch(doSetIncognito(true));
}
dispatch(doPrepareEdit(publishData, uri, fileInfo, fs));
},
clearPlayingUri: () => dispatch(doSetPlayingUri({ uri: null })),
doToast: (options) => dispatch(doToast(options)),
download: (uri) => dispatch(doPlayUri(uri, false, true, () => dispatch(doAnalyticsView(uri)))),
});
export default connect(select, perform)(FileActions); export default connect(select, perform)(FileActions);

View file

@ -5,11 +5,9 @@ import * as MODALS from 'constants/modal_types';
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
import React from 'react'; import React from 'react';
import Button from 'component/button'; import Button from 'component/button';
import FileDownloadLink from 'component/fileDownloadLink';
import { buildURI } from 'util/lbryURI'; import { buildURI } from 'util/lbryURI';
import * as COLLECTIONS_CONSTS from 'constants/collections'; import * as COLLECTIONS_CONSTS from 'constants/collections';
import * as RENDER_MODES from 'constants/file_render_modes'; import * as RENDER_MODES from 'constants/file_render_modes';
import { useIsMobile } from 'effects/use-screensize';
import ClaimSupportButton from 'component/claimSupportButton'; import ClaimSupportButton from 'component/claimSupportButton';
import ClaimCollectionAddButton from 'component/claimCollectionAddButton'; import ClaimCollectionAddButton from 'component/claimCollectionAddButton';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
@ -17,56 +15,60 @@ import FileReactions from 'component/fileReactions';
import { Menu, MenuButton, MenuList, MenuItem } from '@reach/menu-button'; import { Menu, MenuButton, MenuList, MenuItem } from '@reach/menu-button';
import Icon from 'component/common/icon'; import Icon from 'component/common/icon';
import { webDownloadClaim } from 'util/downloadClaim'; import { webDownloadClaim } from 'util/downloadClaim';
import Tooltip from 'component/common/tooltip';
type Props = { type Props = {
uri: string, uri: string,
claim: StreamClaim,
openModal: (id: string, { uri: string, claimIsMine?: boolean, isSupport?: boolean }) => void,
prepareEdit: ({}, string, {}) => void,
claimIsMine: boolean,
fileInfo: FileListItem,
costInfo: ?{ cost: number },
renderMode: string,
hasChannels: boolean,
doToast: ({ message: string }) => void,
clearPlayingUri: () => void,
hideRepost?: boolean, hideRepost?: boolean,
// redux
claim: StreamClaim,
claimIsMine: boolean,
renderMode: string,
costInfo: ?{ cost: number },
hasChannels: boolean,
isLivestreamClaim: boolean, isLivestreamClaim: boolean,
download: (string) => void,
streamingUrl: ?string, streamingUrl: ?string,
disableDownloadButton: boolean, disableDownloadButton: boolean,
doOpenModal: (id: string, { uri: string, claimIsMine?: boolean, isSupport?: boolean }) => void,
doEditForChannel: (claim: Claim, uri: string) => void,
doClearPlayingUri: () => void,
doToast: (data: { message: string }) => void,
doDownloadUri: (uri: string) => void,
}; };
function FileActions(props: Props) { export default function FileActions(props: Props) {
const { const {
fileInfo,
uri, uri,
openModal,
claimIsMine, claimIsMine,
claim, claim,
costInfo, costInfo,
renderMode, renderMode,
prepareEdit,
hasChannels, hasChannels,
clearPlayingUri,
doToast,
hideRepost, hideRepost,
isLivestreamClaim, isLivestreamClaim,
download,
streamingUrl, streamingUrl,
disableDownloadButton, disableDownloadButton,
doOpenModal,
doEditForChannel,
doClearPlayingUri,
doToast,
doDownloadUri,
} = props; } = props;
const { const {
push, push,
location: { pathname, search }, location: { pathname, search },
} = useHistory(); } = useHistory();
const isMobile = useIsMobile();
const webShareable = costInfo && costInfo.cost === 0 && RENDER_MODES.WEB_SHAREABLE_MODES.includes(renderMode); const [downloadClicked, setDownloadClicked] = React.useState(false);
const showDelete = claimIsMine || (fileInfo && (fileInfo.written_bytes > 0 || fileInfo.blobs_completed > 0));
const claimId = claim && claim.claim_id; const { claim_id: claimId, signing_channel: signingChannel, value, meta: claimMeta } = claim;
const { signing_channel: signingChannel } = claim;
const channelName = signingChannel && signingChannel.name; const channelName = signingChannel && signingChannel.name;
const fileName = claim && claim.value && claim.value.source && claim.value.source.name; const fileName = value && value.source && value.source.name;
const webShareable = costInfo && costInfo.cost === 0 && RENDER_MODES.WEB_SHAREABLE_MODES.includes(renderMode);
const urlParams = new URLSearchParams(search);
const collectionId = urlParams.get(COLLECTIONS_CONSTS.COLLECTION_ID);
// We want to use the short form uri for editing // We want to use the short form uri for editing
// This is what the user is used to seeing, they don't care about the claim id // This is what the user is used to seeing, they don't care about the claim id
@ -84,15 +86,9 @@ function FileActions(props: Props) {
editUri = buildURI(uriObject); editUri = buildURI(uriObject);
} }
const urlParams = new URLSearchParams(search);
const collectionId = urlParams.get(COLLECTIONS_CONSTS.COLLECTION_ID);
// @if TARGET='web'
const [downloadClicked, setDownloadClicked] = React.useState(false);
function handleWebDownload() { function handleWebDownload() {
// download() causes 'streamingUrl' to be populated. // doDownloadUri() causes 'streamingUrl' to be populated.
download(uri); doDownloadUri(uri);
setDownloadClicked(true); setDownloadClicked(true);
} }
@ -102,11 +98,10 @@ function FileActions(props: Props) {
setDownloadClicked(false); setDownloadClicked(false);
} }
}, [downloadClicked, streamingUrl, fileName]); }, [downloadClicked, streamingUrl, fileName]);
// @endif
function handleRepostClick() { function handleRepostClick() {
if (!hasChannels) { if (!hasChannels) {
clearPlayingUri(); doClearPlayingUri();
push(`/$/${PAGES.CHANNEL_NEW}?redirect=${pathname}`); push(`/$/${PAGES.CHANNEL_NEW}?redirect=${pathname}`);
doToast({ message: __('A channel is required to repost on %SITE_NAME%', { SITE_NAME }) }); doToast({ message: __('A channel is required to repost on %SITE_NAME%', { SITE_NAME }) });
} else { } else {
@ -114,59 +109,63 @@ function FileActions(props: Props) {
} }
} }
const lhsSection = ( return (
<> <div className="media__actions section__actions--no-margin">
{ENABLE_FILE_REACTIONS && <FileReactions uri={uri} livestream={isLivestreamClaim} />} {ENABLE_FILE_REACTIONS && <FileReactions uri={uri} />}
<ClaimSupportButton uri={uri} fileAction />
<ClaimCollectionAddButton uri={uri} fileAction /> <ClaimSupportButton uri={uri} fileAction />
{!hideRepost && (
<Button <ClaimCollectionAddButton uri={uri} fileAction />
button="alt"
className="button--file-action" {!hideRepost && (
icon={ICONS.REPOST} <Tooltip title={__('Repost')} arrow={false}>
label={ <Button
claim.meta.reposted > 1 ? __(`%repost_total% Reposts`, { repost_total: claim.meta.reposted }) : __('Repost') button="alt"
} className="button--file-action"
description={__('Repost')} icon={ICONS.REPOST}
requiresAuth={IS_WEB} label={
onClick={handleRepostClick} claimMeta.reposted > 1 ? __(`%repost_total% Reposts`, { repost_total: claimMeta.reposted }) : __('Repost')
/> }
)} requiresAuth
<Button onClick={handleRepostClick}
className="button--file-action" />
icon={ICONS.SHARE} </Tooltip>
label={isMobile ? undefined : __('Share')} )}
title={__('Share')}
onClick={() => openModal(MODALS.SOCIAL_SHARE, { uri, webShareable, collectionId })} <Tooltip title={__('Share')} arrow={false}>
/> <Button
</> className="button--file-action"
); icon={ICONS.SHARE}
label={__('Share')}
onClick={() => doOpenModal(MODALS.SOCIAL_SHARE, { uri, webShareable, collectionId })}
/>
</Tooltip>
const rhsSection = (
<>
{/* @if TARGET='app' */}
<FileDownloadLink uri={uri} />
{/* @endif */}
{claimIsMine && ( {claimIsMine && (
<Button <>
className="button--file-action" <Tooltip title={isLivestreamClaim ? __('Update or Publish Replay') : __('Edit')} arrow={false}>
icon={ICONS.EDIT} <div style={{ margin: '0px' }}>
label={isLivestreamClaim ? __('Update or Publish Replay') : __('Edit')} <Button
navigate={`/$/${PAGES.UPLOAD}`} className="button--file-action"
onClick={() => { icon={ICONS.EDIT}
prepareEdit(claim, editUri, fileInfo); label={isLivestreamClaim ? __('Update or Publish Replay') : __('Edit')}
}} navigate={`/$/${PAGES.UPLOAD}`}
/> onClick={() => doEditForChannel(claim, editUri)}
)} />
{showDelete && ( </div>
<Button </Tooltip>
title={__('Remove from your library')}
className="button--file-action" <Tooltip title={__('Remove from your library')} arrow={false}>
icon={ICONS.DELETE} <Button
description={__('Delete')} className="button--file-action"
onClick={() => openModal(MODALS.CONFIRM_FILE_REMOVE, { uri })} icon={ICONS.DELETE}
/> description={__('Delete')}
onClick={() => doOpenModal(MODALS.CONFIRM_FILE_REMOVE, { uri })}
/>
</Tooltip>
</>
)} )}
{(!isLivestreamClaim || !claimIsMine) && ( {(!isLivestreamClaim || !claimIsMine) && (
<Menu> <Menu>
<MenuButton <MenuButton
@ -178,8 +177,8 @@ function FileActions(props: Props) {
> >
<Icon size={20} icon={ICONS.MORE} /> <Icon size={20} icon={ICONS.MORE} />
</MenuButton> </MenuButton>
<MenuList className="menu__list"> <MenuList className="menu__list">
{/* @if TARGET='web' */}
{!isLivestreamClaim && !disableDownloadButton && ( {!isLivestreamClaim && !disableDownloadButton && (
<MenuItem className="comment__menu-option" onSelect={handleWebDownload}> <MenuItem className="comment__menu-option" onSelect={handleWebDownload}>
<div className="menu__link"> <div className="menu__link">
@ -188,7 +187,7 @@ function FileActions(props: Props) {
</div> </div>
</MenuItem> </MenuItem>
)} )}
{/* @endif */}
{!claimIsMine && ( {!claimIsMine && (
<MenuItem <MenuItem
className="comment__menu-option" className="comment__menu-option"
@ -203,26 +202,6 @@ function FileActions(props: Props) {
</MenuList> </MenuList>
</Menu> </Menu>
)} )}
</> </div>
); );
if (isMobile) {
return (
<div className="media__actions">
{lhsSection}
{rhsSection}
</div>
);
} else {
return (
<div className="media__actions">
<div className="section__actions section__actions--no-margin">
{lhsSection}
{rhsSection}
</div>
</div>
);
}
} }
export default FileActions;

View file

@ -7,8 +7,8 @@ import {
makeSelectStreamingUrlForUri, makeSelectStreamingUrlForUri,
} from 'redux/selectors/file_info'; } from 'redux/selectors/file_info';
import { selectCostInfoForUri } from 'lbryinc'; import { selectCostInfoForUri } from 'lbryinc';
import { doOpenModal, doAnalyticsView } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import { doSetPlayingUri, doPlayUri } from 'redux/actions/content'; import { doSetPlayingUri, doDownloadUri } from 'redux/actions/content';
import FileDownloadLink from './view'; import FileDownloadLink from './view';
const select = (state, props) => { const select = (state, props) => {
@ -29,7 +29,7 @@ const select = (state, props) => {
const perform = (dispatch) => ({ const perform = (dispatch) => ({
openModal: (modal, props) => dispatch(doOpenModal(modal, props)), openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
pause: () => dispatch(doSetPlayingUri({ uri: null })), pause: () => dispatch(doSetPlayingUri({ uri: null })),
download: (uri) => dispatch(doPlayUri(uri, false, true, () => dispatch(doAnalyticsView(uri)))), download: (uri) => dispatch(doDownloadUri(uri)),
}); });
export default connect(select, perform)(FileDownloadLink); export default connect(select, perform)(FileDownloadLink);

View file

@ -4,7 +4,7 @@ import * as MODALS from 'constants/modal_types';
// @if TARGET='app' // @if TARGET='app'
import { ipcRenderer } from 'electron'; import { ipcRenderer } from 'electron';
// @endif // @endif
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal, doAnalyticsView } from 'redux/actions/app';
import { makeSelectClaimForUri, selectClaimIsMineForUri, makeSelectClaimWasPurchased } from 'redux/selectors/claims'; import { makeSelectClaimForUri, selectClaimIsMineForUri, makeSelectClaimWasPurchased } from 'redux/selectors/claims';
import { import {
makeSelectFileInfoForUri, makeSelectFileInfoForUri,
@ -105,6 +105,8 @@ export function doSetPrimaryUri(uri: ?string) {
}; };
} }
export const doClearPlayingUri = () => (dispatch: Dispatch) => dispatch(doSetPlayingUri({ uri: null }));
export function doSetPlayingUri({ export function doSetPlayingUri({
uri, uri,
source, source,
@ -142,6 +144,10 @@ export function doPurchaseUriWrapper(uri: string, cost: number, saveFile: boolea
}; };
} }
export function doDownloadUri(uri: string) {
return (dispatch: Dispatch) => dispatch(doPlayUri(uri, false, true, () => dispatch(doAnalyticsView(uri))));
}
export function doPlayUri( export function doPlayUri(
uri: string, uri: string,
skipCostCheck: boolean = false, skipCostCheck: boolean = false,

View file

@ -17,7 +17,7 @@ import { makeSelectPublishFormValue, selectPublishFormValues, selectMyClaimForUr
import { doError } from 'redux/actions/notifications'; import { doError } from 'redux/actions/notifications';
import { push } from 'connected-react-router'; import { push } from 'connected-react-router';
import analytics from 'analytics'; import analytics from 'analytics';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal, doSetIncognito, doSetActiveChannel } from 'redux/actions/app';
import { CC_LICENSES, COPYRIGHT, OTHER, NONE, PUBLIC_DOMAIN } from 'constants/licenses'; import { CC_LICENSES, COPYRIGHT, OTHER, NONE, PUBLIC_DOMAIN } from 'constants/licenses';
import { IMG_CDN_PUBLISH_URL, IMG_CDN_STATUS_URL } from 'constants/cdn_urls'; import { IMG_CDN_PUBLISH_URL, IMG_CDN_STATUS_URL } from 'constants/cdn_urls';
import * as THUMBNAIL_STATUSES from 'constants/thumbnail_upload_statuses'; import * as THUMBNAIL_STATUSES from 'constants/thumbnail_upload_statuses';
@ -530,6 +530,19 @@ export const doUploadThumbnail = (
} }
}; };
export const doEditForChannel = (publishData: any, uri: string, fileInfo: FileListItem, fs: any) => (
dispatch: Dispatch
) => {
if (publishData.signing_channel) {
dispatch(doSetIncognito(false));
dispatch(doSetActiveChannel(publishData.signing_channel.claim_id));
} else {
dispatch(doSetIncognito(true));
}
dispatch(doPrepareEdit(publishData, uri, fileInfo, fs));
};
export const doPrepareEdit = (claim: StreamClaim, uri: string, fileInfo: FileListItem, fs: any) => ( export const doPrepareEdit = (claim: StreamClaim, uri: string, fileInfo: FileListItem, fs: any) => (
dispatch: Dispatch dispatch: Dispatch
) => { ) => {