// @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, channelUri: string, claim: ?Claim, 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, isRepost: boolean, doCollectionEdit: (string, any) => void, hasClaimInWatchLater: boolean, hasClaimInCustom: boolean, claimInCollection: boolean, collectionName?: string, 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, channelUri, claim, openModal, inline = false, doChannelMute, doChannelUnmute, channelIsMuted, channelIsBlocked, channelIsAdminBlocked, isAdmin, doCommentModBlock, doCommentModUnBlock, isRepost, doCommentModBlockAsAdmin, doCommentModUnBlockAsAdmin, doCollectionEdit, hasClaimInWatchLater, hasClaimInCustom, collectionId, collectionName, isMyCollection, doToast, claimIsMine, fileInfo, prepareEdit, isSubscribed, doChannelSubscribe, doChannelUnsubscribe, isChannelPage = false, editedCollection, isAuthenticated, } = props; const repostedContent = claim && claim.reposted_claim; const contentClaim = repostedContent || claim; const incognitoClaim = channelUri && !channelUri.includes('@'); const signingChannel = claim && (claim.signing_channel || claim); const permanentUrl = String(channelUri); const isChannel = !incognitoClaim && signingChannel === claim; const showDelete = claimIsMine || (fileInfo && (fileInfo.written_bytes > 0 || fileInfo.blobs_completed > 0)); const subscriptionLabel = isSubscribed ? __('Unfollow') : __('Follow'); const lastCollectionName = 'Favorites'; 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 handleFollow() { const { channelName } = parseURI(permanentUrl); const subscriptionHandler = isSubscribed ? doChannelUnsubscribe : doChannelSubscribe; subscriptionHandler({ channelName: '@' + channelName, uri: permanentUrl, notificationsDisabled: true, }); } function handleToggleMute() { if (channelIsMuted) { doChannelUnmute(channelUri); } else { doChannelMute(channelUri); } } function handleToggleBlock() { if (channelIsBlocked) { doCommentModUnBlock(channelUri); } else { doCommentModBlock(channelUri); } } function handleEdit() { if (!isChannel) { const signingChannelName = signingChannel && signingChannel.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 (!isRepost && !isChannel) { openModal(MODALS.CONFIRM_FILE_REMOVE, { uri }); } else { openModal(MODALS.CONFIRM_CLAIM_REVOKE, { claim, cb: !isRepost && (() => replace(`/$/${PAGES.CHANNELS}`)) }); } } function handleSupport() { openModal(MODALS.SEND_TIP, { uri, isSupport: true }); } function handleToggleAdminBlock() { if (channelIsAdminBlocked) { doCommentModUnBlockAsAdmin(channelUri, ''); } else { doCommentModBlockAsAdmin(channelUri, ''); } } 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=${(repostedContent && repostedContent.claim_id) || claim.claim_id}`); } return ( { e.stopPropagation(); e.preventDefault(); }} > {(!IS_WEB || (IS_WEB && isAuthenticated)) && ( <> <> {/* WATCH LATER */} {isPlayable && !collectionId && ( { doToast({ message: hasClaimInWatchLater ? __('Item removed from Watch Later') : __('Item added to Watch Later'), }); doCollectionEdit(COLLECTIONS_CONSTS.WATCH_LATER_ID, { claims: [contentClaim], remove: hasClaimInWatchLater, type: 'playlist', }); }} >
{hasClaimInWatchLater ? __('In Watch Later') : __('Watch Later')}
)} {/* CUSTOM LIST */} {isPlayable && !collectionId && ( { doToast({ message: hasClaimInCustom ? __('Item removed from %lastCollectionName%', { lastCollectionName }) : __('Item added to %lastCollectionName%', { lastCollectionName }), }); doCollectionEdit(COLLECTIONS_CONSTS.FAVORITES_ID, { claims: [contentClaim], remove: hasClaimInCustom, type: 'playlist', }); }} >
{hasClaimInCustom ? __('In %lastCollectionName%', { lastCollectionName }) : __(`${lastCollectionName}`)}
)} {/* COLLECTION OPERATIONS */} {collectionId && collectionName && isCollectionClaim && ( <> {Boolean(editedCollection) && ( push(`/$/${PAGES.LIST}/${collectionId}?view=edit`)} >
{__('Publish')}
)} push(`/$/${PAGES.LIST}/${collectionId}`)}>
{__('View List')}
openModal(MODALS.COLLECTION_DELETE, { collectionId })} >
{__('Delete List')}
)} {/* CURRENTLY ONLY SUPPORT PLAYLISTS FOR PLAYABLE; LATER DIFFERENT TYPES */} {isPlayable && ( openModal(MODALS.COLLECTION_ADD, { uri, type: 'playlist' })} >
{__('Add to Lists')}
)} {!isChannelPage && ( <>
{__('Support --[button to support a claim]--')}
)} {!incognitoClaim && !isRepost && !claimIsMine && !isChannelPage && ( <>
{subscriptionLabel}
)} {!isMyCollection && ( <> {(!claimIsMine || channelIsBlocked) && channelUri ? ( !incognitoClaim && !isRepost && ( <>
{channelIsBlocked ? __('Unblock Channel') : __('Block Channel')}
{isAdmin && (
{channelIsAdminBlocked ? __('Global Unblock Channel') : __('Global Block Channel')}
)}
{channelIsMuted ? __('Unmute Channel') : __('Mute Channel')}
) ) : ( <> {!isChannelPage && !isRepost && (
{__('Edit')}
)} {showDelete && (
{__('Delete')}
)} )} )} )}
{isChannelPage && IS_WEB && rssUrl && (
{__('Copy RSS URL')}
)}
{__('Copy Link')}
{!claimIsMine && !isMyCollection && (
{__('Report Content')}
)}
); } export default ClaimMenuList;