2019-06-11 20:10:58 +02:00
|
|
|
// @flow
|
|
|
|
import React, { useEffect } from 'react';
|
|
|
|
import classnames from 'classnames';
|
2019-06-27 08:18:45 +02:00
|
|
|
import { parseURI, convertToShareLink } from 'lbry-redux';
|
2019-06-11 20:10:58 +02:00
|
|
|
import { withRouter } from 'react-router-dom';
|
|
|
|
import { openCopyLinkMenu } from 'util/context-menu';
|
|
|
|
import { formatLbryUriForWeb } from 'util/uri';
|
|
|
|
import CardMedia from 'component/cardMedia';
|
|
|
|
import UriIndicator from 'component/uriIndicator';
|
|
|
|
import TruncatedText from 'component/common/truncated-text';
|
|
|
|
import DateTime from 'component/dateTime';
|
|
|
|
import FileProperties from 'component/fileProperties';
|
2019-06-19 07:05:43 +02:00
|
|
|
import ClaimTags from 'component/claimTags';
|
2019-06-11 20:10:58 +02:00
|
|
|
import SubscribeButton from 'component/subscribeButton';
|
|
|
|
import ChannelThumbnail from 'component/channelThumbnail';
|
|
|
|
|
|
|
|
type Props = {
|
|
|
|
uri: string,
|
|
|
|
claim: ?Claim,
|
|
|
|
obscureNsfw: boolean,
|
|
|
|
claimIsMine: boolean,
|
|
|
|
pending?: boolean,
|
|
|
|
resolveUri: string => void,
|
|
|
|
isResolvingUri: boolean,
|
|
|
|
preventResolve: boolean,
|
|
|
|
history: { push: string => void },
|
|
|
|
thumbnail: string,
|
|
|
|
title: string,
|
|
|
|
nsfw: boolean,
|
|
|
|
placeholder: boolean,
|
2019-06-19 07:05:43 +02:00
|
|
|
type: string,
|
2019-07-11 20:06:25 +02:00
|
|
|
hasVisitedUri: boolean,
|
2019-06-28 09:27:55 +02:00
|
|
|
blackListedOutpoints: Array<{
|
|
|
|
txid: string,
|
|
|
|
nout: number,
|
|
|
|
}>,
|
2019-07-17 05:32:29 +02:00
|
|
|
filteredOutpoints: Array<{
|
|
|
|
txid: string,
|
|
|
|
nout: number,
|
|
|
|
}>,
|
2019-06-11 20:10:58 +02:00
|
|
|
};
|
|
|
|
|
2019-06-28 09:27:55 +02:00
|
|
|
function ClaimPreview(props: Props) {
|
2019-06-11 20:10:58 +02:00
|
|
|
const {
|
|
|
|
obscureNsfw,
|
|
|
|
claimIsMine,
|
|
|
|
pending,
|
|
|
|
history,
|
|
|
|
uri,
|
|
|
|
isResolvingUri,
|
|
|
|
thumbnail,
|
|
|
|
title,
|
|
|
|
nsfw,
|
|
|
|
resolveUri,
|
|
|
|
claim,
|
|
|
|
placeholder,
|
2019-06-19 07:05:43 +02:00
|
|
|
type,
|
2019-06-28 09:27:55 +02:00
|
|
|
blackListedOutpoints,
|
2019-07-17 05:32:29 +02:00
|
|
|
filteredOutpoints,
|
2019-07-11 20:06:25 +02:00
|
|
|
hasVisitedUri,
|
2019-06-11 20:10:58 +02:00
|
|
|
} = props;
|
|
|
|
const haventFetched = claim === undefined;
|
2019-06-27 08:18:45 +02:00
|
|
|
const abandoned = !isResolvingUri && !claim && !placeholder;
|
2019-06-11 20:10:58 +02:00
|
|
|
const claimsInChannel = (claim && claim.meta.claims_in_channel) || 0;
|
2019-07-11 21:03:31 +02:00
|
|
|
let isValid;
|
|
|
|
try {
|
|
|
|
parseURI(uri);
|
|
|
|
isValid = true;
|
|
|
|
} catch (e) {
|
|
|
|
isValid = false;
|
|
|
|
}
|
2019-07-05 20:11:55 +02:00
|
|
|
|
2019-07-11 21:03:31 +02:00
|
|
|
const isChannel = isValid ? parseURI(uri).isChannel : false;
|
2019-07-25 22:26:42 +02:00
|
|
|
const signingChannel = claim && claim.signing_channel;
|
|
|
|
|
2019-07-05 20:11:55 +02:00
|
|
|
let shouldHide = abandoned || (!claimIsMine && obscureNsfw && nsfw);
|
|
|
|
|
|
|
|
// This will be replaced once blocking is done at the wallet server level
|
|
|
|
if (claim && !shouldHide && blackListedOutpoints) {
|
2019-07-17 05:32:29 +02:00
|
|
|
shouldHide = blackListedOutpoints.some(outpoint => outpoint.txid === claim.txid && outpoint.nout === claim.nout);
|
|
|
|
}
|
2019-07-25 22:26:42 +02:00
|
|
|
// We're checking to see if the stream outpoint
|
|
|
|
// or signing channel outpoint is in the filter list
|
2019-07-17 05:32:29 +02:00
|
|
|
if (claim && !shouldHide && filteredOutpoints) {
|
2019-07-25 22:26:42 +02:00
|
|
|
shouldHide = filteredOutpoints.some(
|
|
|
|
outpoint =>
|
|
|
|
(signingChannel && outpoint.txid === signingChannel.txid && outpoint.nout === signingChannel.nout) ||
|
|
|
|
(outpoint.txid === claim.txid && outpoint.nout === claim.nout)
|
|
|
|
);
|
2019-07-05 20:11:55 +02:00
|
|
|
}
|
2019-06-11 20:10:58 +02:00
|
|
|
|
|
|
|
function handleContextMenu(e) {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
if (claim) {
|
|
|
|
openCopyLinkMenu(convertToShareLink(claim.permanent_url), e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function onClick(e) {
|
|
|
|
if ((isChannel || title) && !pending) {
|
|
|
|
history.push(formatLbryUriForWeb(uri));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
useEffect(() => {
|
2019-07-11 21:03:31 +02:00
|
|
|
if (isValid && !isResolvingUri && haventFetched && uri) {
|
2019-06-11 20:10:58 +02:00
|
|
|
resolveUri(uri);
|
|
|
|
}
|
2019-07-17 22:49:06 +02:00
|
|
|
}, [isValid, isResolvingUri, uri, resolveUri, haventFetched]);
|
2019-06-11 20:10:58 +02:00
|
|
|
|
|
|
|
if (shouldHide) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2019-07-17 22:49:06 +02:00
|
|
|
if (placeholder || (isResolvingUri && !claim)) {
|
2019-06-11 20:10:58 +02:00
|
|
|
return (
|
2019-06-27 08:18:45 +02:00
|
|
|
<li className="claim-preview" disabled>
|
2019-06-11 20:10:58 +02:00
|
|
|
<div className="placeholder media__thumb" />
|
|
|
|
<div className="placeholder__wrapper">
|
2019-06-27 08:18:45 +02:00
|
|
|
<div className="placeholder claim-preview-title" />
|
2019-06-11 20:10:58 +02:00
|
|
|
<div className="placeholder media__subtitle" />
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<li
|
|
|
|
role="link"
|
2019-06-28 09:27:55 +02:00
|
|
|
onClick={pending ? undefined : onClick}
|
2019-06-11 20:10:58 +02:00
|
|
|
onContextMenu={handleContextMenu}
|
2019-06-27 08:18:45 +02:00
|
|
|
className={classnames('claim-preview', {
|
|
|
|
'claim-preview--large': type === 'large',
|
2019-07-11 21:03:31 +02:00
|
|
|
'claim-preview--visited': !isChannel && hasVisitedUri,
|
2019-07-11 20:06:25 +02:00
|
|
|
'claim-preview--pending': pending,
|
2019-06-11 20:10:58 +02:00
|
|
|
})}
|
|
|
|
>
|
|
|
|
{isChannel ? <ChannelThumbnail uri={uri} /> : <CardMedia thumbnail={thumbnail} />}
|
2019-06-27 08:18:45 +02:00
|
|
|
<div className="claim-preview-metadata">
|
|
|
|
<div className="claim-preview-info">
|
|
|
|
<div className="claim-preview-title">
|
2019-06-11 20:10:58 +02:00
|
|
|
<TruncatedText text={title || (claim && claim.name)} lines={1} />
|
|
|
|
</div>
|
2019-06-19 07:05:43 +02:00
|
|
|
{type !== 'small' && (
|
2019-06-11 20:10:58 +02:00
|
|
|
<div>
|
|
|
|
{isChannel && <SubscribeButton uri={uri.startsWith('lbry://') ? uri : `lbry://${uri}`} />}
|
2019-06-17 22:32:38 +02:00
|
|
|
{!isChannel && <FileProperties uri={uri} />}
|
2019-06-11 20:10:58 +02:00
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
|
2019-06-27 08:18:45 +02:00
|
|
|
<div className="claim-preview-properties">
|
2019-06-11 20:10:58 +02:00
|
|
|
<div className="media__subtitle">
|
|
|
|
<UriIndicator uri={uri} link />
|
|
|
|
{pending && <div>Pending...</div>}
|
|
|
|
<div>{isChannel ? `${claimsInChannel} ${__('publishes')}` : <DateTime timeAgo uri={uri} />}</div>
|
|
|
|
</div>
|
|
|
|
|
2019-06-19 07:05:43 +02:00
|
|
|
<ClaimTags uri={uri} type={type} />
|
2019-06-11 20:10:58 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-06-28 09:27:55 +02:00
|
|
|
export default withRouter(ClaimPreview);
|