lbry-desktop/ui/component/claimMenuList/view.jsx
saltrafael b164a5d1f4 Pop up Menu Fixes and Improvements
Pop up Menu Fixes and Improvements

Improve re-directs

Fix file deletion

Improve code, and more

Fix List Layout collection popup

Allow to edit list

Fix blocking when not logged or no channel

Fix Edit and Delete showing for not owned Lists

Fix actions breaking when not logged in

Fix List options not showing

Lint

Shorten logic

Lint
2021-07-21 14:40:44 -04:00

424 lines
14 KiB
JavaScript

// @flow
import { URL, SHARE_DOMAIN_URL } from 'config';
import * as ICONS from 'constants/icons';
import * as PAGES from 'constants/pages';
import * as MODALS from 'constants/modal_types';
import React from 'react';
import classnames from 'classnames';
import { Menu, MenuButton, MenuList, MenuItem } from '@reach/menu-button';
import Icon from 'component/common/icon';
import { generateShareUrl, generateRssUrl, generateLbryContentUrl } from 'util/url';
import { useHistory } from 'react-router';
import { buildURI, parseURI, COLLECTIONS_CONSTS } from 'lbry-redux';
const SHARE_DOMAIN = SHARE_DOMAIN_URL || URL;
const PAGE_VIEW_QUERY = `view`;
const EDIT_PAGE = 'edit';
type SubscriptionArgs = {
channelName: string,
uri: string,
notificationsDisabled?: boolean,
};
type Props = {
uri: string,
claim: ?Claim,
repostedClaim: ?Claim,
contentClaim: ?Claim,
contentSigningChannel: ?Claim,
contentChannelUri: string,
openModal: (id: string, {}) => void,
inline?: boolean,
channelIsMuted: boolean,
channelIsBlocked: boolean,
channelIsAdminBlocked: boolean,
isAdmin: boolean,
doChannelMute: (string) => void,
doChannelUnmute: (string) => void,
doCommentModBlock: (string) => void,
doCommentModUnBlock: (string) => void,
doCommentModBlockAsAdmin: (string, string) => void,
doCommentModUnBlockAsAdmin: (string, string) => void,
doCollectionEdit: (string, any) => void,
hasClaimInWatchLater: boolean,
hasClaimInCustom: boolean,
claimInCollection: boolean,
collectionId: string,
isMyCollection: boolean,
doToast: ({ message: string, isError?: boolean }) => void,
claimIsMine: boolean,
fileInfo: FileListItem,
prepareEdit: ({}, string, {}) => void,
isSubscribed: boolean,
doChannelSubscribe: (SubscriptionArgs) => void,
doChannelUnsubscribe: (SubscriptionArgs) => void,
isChannelPage: boolean,
editedCollection: Collection,
isAuthenticated: boolean,
};
function ClaimMenuList(props: Props) {
const {
uri,
claim,
repostedClaim,
contentClaim,
contentSigningChannel,
contentChannelUri,
openModal,
inline = false,
doChannelMute,
doChannelUnmute,
channelIsMuted,
channelIsBlocked,
channelIsAdminBlocked,
isAdmin,
doCommentModBlock,
doCommentModUnBlock,
doCommentModBlockAsAdmin,
doCommentModUnBlockAsAdmin,
doCollectionEdit,
hasClaimInWatchLater,
hasClaimInCustom,
collectionId,
isMyCollection,
doToast,
claimIsMine,
fileInfo,
prepareEdit,
isSubscribed,
doChannelSubscribe,
doChannelUnsubscribe,
isChannelPage = false,
editedCollection,
isAuthenticated,
} = props;
const incognitoClaim = contentChannelUri && !contentChannelUri.includes('@');
const isChannel = !incognitoClaim && !contentSigningChannel;
const { channelName } = parseURI(contentChannelUri);
const showDelete = claimIsMine || (fileInfo && (fileInfo.written_bytes > 0 || fileInfo.blobs_completed > 0));
const subscriptionLabel = __('%action%' + '%user%', {
action: isSubscribed ? __('Unfollow') : __('Follow'),
user: repostedClaim ? __(' @' + channelName) : '',
});
const lastCollectionName = 'Favorites';
const lastCollectionId = COLLECTIONS_CONSTS.FAVORITES_ID;
const { push, replace } = useHistory();
if (!claim) {
return null;
}
const lbryUrl: string = generateLbryContentUrl(claim.canonical_url, claim.permanent_url);
const shareUrl: string = generateShareUrl(SHARE_DOMAIN, lbryUrl);
const rssUrl: string = isChannel ? generateRssUrl(SHARE_DOMAIN, claim) : '';
const isCollectionClaim = claim && claim.value_type === 'collection';
// $FlowFixMe
const isPlayable =
contentClaim &&
// $FlowFixMe
contentClaim.value &&
// $FlowFixMe
contentClaim.value.stream_type &&
// $FlowFixMe
(contentClaim.value.stream_type === 'audio' || contentClaim.value.stream_type === 'video');
function handleAdd(source, name, collectionId) {
doToast({
message: source ? __('Item removed from %name%', { name }) : __('Item added to %name%', { name }),
});
doCollectionEdit(collectionId, {
claims: [contentClaim],
remove: source,
type: 'playlist',
});
}
function handleFollow() {
const subscriptionHandler = isSubscribed ? doChannelUnsubscribe : doChannelSubscribe;
subscriptionHandler({
channelName: '@' + channelName,
uri: contentChannelUri,
notificationsDisabled: true,
});
}
function handleToggleMute() {
if (channelIsMuted) {
doChannelUnmute(contentChannelUri);
} else {
doChannelMute(contentChannelUri);
}
}
function handleToggleBlock() {
if (channelIsBlocked) {
doCommentModUnBlock(contentChannelUri);
} else {
doCommentModBlock(contentChannelUri);
}
}
function handleEdit() {
if (!isChannel) {
const signingChannelName = contentSigningChannel && contentSigningChannel.name;
const uriObject: { streamName: string, streamClaimId: string, channelName?: string } = {
streamName: claim.name,
streamClaimId: claim.claim_id,
};
if (signingChannelName) {
uriObject.channelName = signingChannelName;
}
const editUri = buildURI(uriObject);
push(`/$/${PAGES.UPLOAD}`);
prepareEdit(claim, editUri, fileInfo);
} else {
const channelUrl = claim.name + ':' + claim.claim_id;
push(`/${channelUrl}?${PAGE_VIEW_QUERY}=${EDIT_PAGE}`);
}
}
function handleDelete() {
if (!repostedClaim && !isChannel) {
openModal(MODALS.CONFIRM_FILE_REMOVE, { uri, doGoBack: false });
} else {
openModal(MODALS.CONFIRM_CLAIM_REVOKE, { claim, cb: isChannel && (() => replace(`/$/${PAGES.CHANNELS}`)) });
}
}
function handleSupport() {
openModal(MODALS.SEND_TIP, { uri, isSupport: true });
}
function handleToggleAdminBlock() {
if (channelIsAdminBlocked) {
doCommentModUnBlockAsAdmin(contentChannelUri, '');
} else {
doCommentModBlockAsAdmin(contentChannelUri, '');
}
}
function copyToClipboard(textToCopy, successMsg, failureMsg) {
navigator.clipboard
.writeText(textToCopy)
.then(() => {
doToast({ message: __(successMsg) });
})
.catch(() => {
doToast({ message: __(failureMsg), isError: true });
});
}
function handleCopyRssLink() {
copyToClipboard(rssUrl, 'RSS URL copied.', 'Failed to copy RSS URL.');
}
function handleCopyLink() {
copyToClipboard(shareUrl, 'Link copied.', 'Failed to copy link.');
}
function handleReportContent() {
// $FlowFixMe
push(`/$/${PAGES.REPORT_CONTENT}?claimId=${contentClaim && contentClaim.claim_id}`);
}
return (
<Menu>
<MenuButton
className={classnames('menu__button', { 'claim__menu-button': !inline, 'claim__menu-button--inline': inline })}
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
}}
>
<Icon size={20} icon={ICONS.MORE_VERTICAL} />
</MenuButton>
<MenuList className="menu__list">
{(!IS_WEB || (IS_WEB && isAuthenticated)) && (
<>
<>
{/* COLLECTION OPERATIONS */}
{collectionId && isCollectionClaim ? (
<>
<MenuItem className="comment__menu-option" onSelect={() => push(`/$/${PAGES.LIST}/${collectionId}`)}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.VIEW} />
{__('View List')}
</div>
</MenuItem>
{isMyCollection && (
<>
<MenuItem
className="comment__menu-option"
onSelect={() => push(`/$/${PAGES.LIST}/${collectionId}?view=edit`)}
>
<div className="menu__link">
<Icon aria-hidden iconColor={'red'} icon={ICONS.PUBLISH} />
{editedCollection ? __('Publish') : __('Edit List')}
</div>
</MenuItem>
<MenuItem
className="comment__menu-option"
onSelect={() => openModal(MODALS.COLLECTION_DELETE, { collectionId })}
>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.DELETE} />
{__('Delete List')}
</div>
</MenuItem>
</>
)}
</>
) : (
isPlayable && (
<>
{/* WATCH LATER */}
<MenuItem
className="comment__menu-option"
onSelect={() => handleAdd(hasClaimInWatchLater, 'Watch Later', COLLECTIONS_CONSTS.WATCH_LATER_ID)}
>
<div className="menu__link">
<Icon aria-hidden icon={hasClaimInWatchLater ? ICONS.DELETE : ICONS.TIME} />
{hasClaimInWatchLater ? __('In Watch Later') : __('Watch Later')}
</div>
</MenuItem>
{/* CUSTOM LIST */}
<MenuItem
className="comment__menu-option"
onSelect={() => handleAdd(hasClaimInCustom, lastCollectionName, lastCollectionId)}
>
<div className="menu__link">
<Icon aria-hidden icon={hasClaimInCustom ? ICONS.DELETE : ICONS.STAR} />
{hasClaimInCustom ? __(`In ${lastCollectionName}`) : __(`${lastCollectionName}`)}
</div>
</MenuItem>
{/* CURRENTLY ONLY SUPPORT PLAYLISTS FOR PLAYABLE; LATER DIFFERENT TYPES */}
<MenuItem
className="comment__menu-option"
onSelect={() => openModal(MODALS.COLLECTION_ADD, { uri, type: 'playlist' })}
>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.STACK} />
{__('Add to Lists')}
</div>
</MenuItem>
<hr className="menu__separator" />
</>
)
)}
</>
{!isChannelPage && (
<>
<MenuItem className="comment__menu-option" onSelect={handleSupport}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.LBC} />
{__('Support --[button to support a claim]--')}
</div>
</MenuItem>
</>
)}
{!incognitoClaim && !claimIsMine && !isChannelPage && (
<>
<hr className="menu__separator" />
<MenuItem className="comment__menu-option" onSelect={handleFollow}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.SUBSCRIBE} />
{subscriptionLabel}
</div>
</MenuItem>
</>
)}
{!isMyCollection && (
<>
{(!claimIsMine || channelIsBlocked) && contentChannelUri ? (
!incognitoClaim && (
<>
<hr className="menu__separator" />
<MenuItem className="comment__menu-option" onSelect={handleToggleBlock}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.BLOCK} />
{channelIsBlocked ? __('Unblock Channel') : __('Block Channel')}
</div>
</MenuItem>
{isAdmin && (
<MenuItem className="comment__menu-option" onSelect={handleToggleAdminBlock}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.GLOBE} />
{channelIsAdminBlocked ? __('Global Unblock Channel') : __('Global Block Channel')}
</div>
</MenuItem>
)}
<MenuItem className="comment__menu-option" onSelect={handleToggleMute}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.MUTE} />
{channelIsMuted ? __('Unmute Channel') : __('Mute Channel')}
</div>
</MenuItem>
</>
)
) : (
<>
{!isChannelPage && !repostedClaim && (
<MenuItem className="comment__menu-option" onSelect={handleEdit}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.EDIT} />
{__('Edit')}
</div>
</MenuItem>
)}
{showDelete && (
<MenuItem className="comment__menu-option" onSelect={handleDelete}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.DELETE} />
{__('Delete')}
</div>
</MenuItem>
)}
</>
)}
</>
)}
</>
)}
<hr className="menu__separator" />
{isChannelPage && IS_WEB && rssUrl && (
<MenuItem className="comment__menu-option" onSelect={handleCopyRssLink}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.RSS} />
{__('Copy RSS URL')}
</div>
</MenuItem>
)}
<MenuItem className="comment__menu-option" onSelect={handleCopyLink}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.SHARE} />
{__('Copy Link')}
</div>
</MenuItem>
{!claimIsMine && !isMyCollection && (
<MenuItem className="comment__menu-option" onSelect={handleReportContent}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.REPORT} />
{__('Report Content')}
</div>
</MenuItem>
)}
</MenuList>
</Menu>
);
}
export default ClaimMenuList;