Thumbnail fixes #6969
7 changed files with 83 additions and 38 deletions
|
@ -108,7 +108,7 @@ function ChannelForm(props: Props) {
|
||||||
if (isClaimingInitialRewards) {
|
if (isClaimingInitialRewards) {
|
||||||
return __('Claiming credits...');
|
return __('Claiming credits...');
|
||||||
}
|
}
|
||||||
return creatingChannel || updatingChannel ? __('Submitting') : __('Submit');
|
return creatingChannel || updatingChannel ? __('Submitting...') : __('Submit');
|
||||||
}, [isClaimingInitialRewards, creatingChannel, updatingChannel]);
|
}, [isClaimingInitialRewards, creatingChannel, updatingChannel]);
|
||||||
const submitDisabled = React.useMemo(() => {
|
const submitDisabled = React.useMemo(() => {
|
||||||
return (
|
return (
|
||||||
|
@ -121,7 +121,17 @@ function ChannelForm(props: Props) {
|
||||||
bidError ||
|
bidError ||
|
||||||
(isNewChannel && !params.name)
|
(isNewChannel && !params.name)
|
||||||
);
|
);
|
||||||
}, [isClaimingInitialRewards, creatingChannel, updatingChannel, nameError, thumbError, coverError, bidError, isNewChannel, params.name]);
|
}, [
|
||||||
|
isClaimingInitialRewards,
|
||||||
|
creatingChannel,
|
||||||
|
updatingChannel,
|
||||||
|
nameError,
|
||||||
|
thumbError,
|
||||||
|
coverError,
|
||||||
|
bidError,
|
||||||
|
isNewChannel,
|
||||||
|
params.name,
|
||||||
|
]);
|
||||||
|
|
||||||
function getChannelParams() {
|
function getChannelParams() {
|
||||||
// fill this in with sdk data
|
// fill this in with sdk data
|
||||||
|
@ -297,13 +307,8 @@ function ChannelForm(props: Props) {
|
||||||
(coverError && isUpload.cover ? (
|
(coverError && isUpload.cover ? (
|
||||||
<div className="channel-cover__custom--waiting">{__('This will be visible in a few minutes.')}</div>
|
<div className="channel-cover__custom--waiting">{__('This will be visible in a few minutes.')}</div>
|
||||||
) : (
|
) : (
|
||||||
<img
|
<img className="channel-cover__custom" src={coverSrc} onError={() => setCoverError(true)} />
|
||||||
className="channel-cover__custom"
|
))}
|
||||||
src={coverSrc}
|
|
||||||
onError={() => setCoverError(true)}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
<div className="channel__primary-info">
|
<div className="channel__primary-info">
|
||||||
<div className="channel__edit-thumb">
|
<div className="channel__edit-thumb">
|
||||||
<Button
|
<Button
|
||||||
|
@ -328,8 +333,8 @@ function ChannelForm(props: Props) {
|
||||||
thumbnailPreview={thumbnailPreview}
|
thumbnailPreview={thumbnailPreview}
|
||||||
allowGifs
|
allowGifs
|
||||||
showDelayedMessage={isUpload.thumbnail}
|
showDelayedMessage={isUpload.thumbnail}
|
||||||
setThumbError={(v) => setThumbError(v)}
|
setThumbUploadError={setThumbError}
|
||||||
thumbError={thumbError}
|
thumbUploadError={thumbError}
|
||||||
/>
|
/>
|
||||||
<h1 className="channel__title">
|
<h1 className="channel__title">
|
||||||
{params.title || (channelName && '@' + channelName) || (params.name && '@' + params.name)}
|
{params.title || (channelName && '@' + channelName) || (params.name && '@' + params.name)}
|
||||||
|
|
|
@ -25,8 +25,8 @@ type Props = {
|
||||||
hideStakedIndicator?: boolean,
|
hideStakedIndicator?: boolean,
|
||||||
xsmall?: boolean,
|
xsmall?: boolean,
|
||||||
noOptimization?: boolean,
|
noOptimization?: boolean,
|
||||||
setThumbError: (boolean) => void,
|
setThumbUploadError: (boolean) => void,
|
||||||
thumbError: boolean,
|
ThumbUploadError: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
function ChannelThumbnail(props: Props) {
|
function ChannelThumbnail(props: Props) {
|
||||||
|
@ -45,13 +45,15 @@ function ChannelThumbnail(props: Props) {
|
||||||
showDelayedMessage = false,
|
showDelayedMessage = false,
|
||||||
noLazyLoad,
|
noLazyLoad,
|
||||||
hideStakedIndicator = false,
|
hideStakedIndicator = false,
|
||||||
setThumbError,
|
setThumbUploadError,
|
||||||
|
ThumbUploadError,
|
||||||
} = props;
|
} = props;
|
||||||
|
const [thumbLoadError, setThumbLoadError] = React.useState(ThumbUploadError);
|
||||||
const shouldResolve = claim === undefined;
|
const shouldResolve = claim === undefined;
|
||||||
const thumbnail = rawThumbnail && rawThumbnail.trim().replace(/^http:\/\//i, 'https://');
|
const thumbnail = rawThumbnail && rawThumbnail.trim().replace(/^http:\/\//i, 'https://');
|
||||||
const thumbnailPreview = rawThumbnailPreview && rawThumbnailPreview.trim().replace(/^http:\/\//i, 'https://');
|
const thumbnailPreview = rawThumbnailPreview && rawThumbnailPreview.trim().replace(/^http:\/\//i, 'https://');
|
||||||
const defaultAvater = AVATAR_DEFAULT || Gerbil;
|
const defaultAvatar = AVATAR_DEFAULT || Gerbil;
|
||||||
const channelThumbnail = thumbnailPreview || thumbnail || defaultAvater;
|
const channelThumbnail = thumbnailPreview || thumbnail || defaultAvatar;
|
||||||
const isGif = channelThumbnail && channelThumbnail.endsWith('gif');
|
const isGif = channelThumbnail && channelThumbnail.endsWith('gif');
|
||||||
const showThumb = (!obscure && !!thumbnail) || thumbnailPreview;
|
const showThumb = (!obscure && !!thumbnail) || thumbnailPreview;
|
||||||
|
|
||||||
|
@ -91,13 +93,19 @@ function ChannelThumbnail(props: Props) {
|
||||||
>
|
>
|
||||||
{showDelayedMessage ? (
|
{showDelayedMessage ? (
|
||||||
<div className="channel-thumbnail--waiting">{__('This will be visible in a few minutes.')}</div>
|
<div className="channel-thumbnail--waiting">{__('This will be visible in a few minutes.')}</div>
|
||||||
) : (
|
) : (
|
||||||
<OptimizedImage
|
<OptimizedImage
|
||||||
alt={__('Channel profile picture')}
|
alt={__('Channel profile picture')}
|
||||||
className={!channelThumbnail ? 'channel-thumbnail__default' : 'channel-thumbnail__custom'}
|
className={!channelThumbnail ? 'channel-thumbnail__default' : 'channel-thumbnail__custom'}
|
||||||
src={channelThumbnail}
|
src={(!thumbLoadError && channelThumbnail) || defaultAvatar}
|
||||||
loading={noLazyLoad ? undefined : 'lazy'}
|
loading={noLazyLoad ? undefined : 'lazy'}
|
||||||
onError={() => setThumbError(true)}
|
onError={() => {
|
||||||
|
if (setThumbUploadError) {
|
||||||
|
setThumbUploadError(true);
|
||||||
|
} else {
|
||||||
|
setThumbLoadError(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!hideStakedIndicator && <ChannelStakedIndicator uri={uri} claim={claim} />}
|
{!hideStakedIndicator && <ChannelStakedIndicator uri={uri} claim={claim} />}
|
||||||
|
|
|
@ -224,6 +224,7 @@ function PublishForm(props: Props) {
|
||||||
(activeChannelClaim && activeChannelClaim.claim_id);
|
(activeChannelClaim && activeChannelClaim.claim_id);
|
||||||
|
|
||||||
const nameEdited = isStillEditing && name !== prevName;
|
const nameEdited = isStillEditing && name !== prevName;
|
||||||
|
const thumbnailUploaded = uploadThumbnailStatus === THUMBNAIL_STATUSES.COMPLETE && thumbnail;
|
||||||
|
|
||||||
const waitingForFile = waitForFile && !remoteUrl && !filePath;
|
const waitingForFile = waitForFile && !remoteUrl && !filePath;
|
||||||
// If they are editing, they don't need a new file chosen
|
// If they are editing, they don't need a new file chosen
|
||||||
|
@ -235,7 +236,7 @@ function PublishForm(props: Props) {
|
||||||
thumbnail &&
|
thumbnail &&
|
||||||
!bidError &&
|
!bidError &&
|
||||||
!emptyPostError &&
|
!emptyPostError &&
|
||||||
!thumbnailError &&
|
!(thumbnailError && !thumbnailUploaded) &&
|
||||||
!(uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS);
|
!(uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS);
|
||||||
|
|
||||||
const isOverwritingExistingClaim = !editingURI && myClaimForUri;
|
const isOverwritingExistingClaim = !editingURI && myClaimForUri;
|
||||||
|
|
|
@ -35,6 +35,7 @@ function PublishFormErrors(props: Props) {
|
||||||
// If there is an error it will be presented as an inline error as well
|
// If there is an error it will be presented as an inline error as well
|
||||||
|
|
||||||
const isUploadingThumbnail = uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS;
|
const isUploadingThumbnail = uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS;
|
||||||
|
const thumbnailUploaded = uploadThumbnailStatus === THUMBNAIL_STATUSES.COMPLETE && thumbnail;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="error__text">
|
<div className="error__text">
|
||||||
|
@ -48,7 +49,7 @@ function PublishFormErrors(props: Props) {
|
||||||
{!isUploadingThumbnail && !thumbnail && (
|
{!isUploadingThumbnail && !thumbnail && (
|
||||||
<div>{__('A thumbnail is required. Please upload or provide an image URL above.')}</div>
|
<div>{__('A thumbnail is required. Please upload or provide an image URL above.')}</div>
|
||||||
)}
|
)}
|
||||||
{thumbnailError && <div>{__('Thumbnail is invalid.')}</div>}
|
{thumbnailError && !thumbnailUploaded && <div>{__('Thumbnail is invalid.')}</div>}
|
||||||
{editingURI && !isStillEditing && !filePath && (
|
{editingURI && !isStillEditing && !filePath && (
|
||||||
<div>{__('Please reselect a file after changing the LBRY URL')}</div>
|
<div>{__('Please reselect a file after changing the LBRY URL')}</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -68,13 +68,13 @@ class SelectThumbnail extends React.PureComponent<Props> {
|
||||||
isSupportedVideo = actualFilePath.type.split('/')[0] === 'video';
|
isSupportedVideo = actualFilePath.type.split('/')[0] === 'video';
|
||||||
}
|
}
|
||||||
|
|
||||||
let thumbnailSrc;
|
let thumbnailInputSrc;
|
||||||
if (!thumbnail) {
|
if (!thumbnail) {
|
||||||
thumbnailSrc = ThumbnailMissingImage;
|
thumbnailInputSrc = ThumbnailMissingImage;
|
||||||
} else if (thumbnailError) {
|
} else if (thumbnailError) {
|
||||||
thumbnailSrc = ThumbnailBrokenImage;
|
thumbnailInputSrc = ThumbnailBrokenImage;
|
||||||
} else {
|
} else {
|
||||||
thumbnailSrc = thumbnail;
|
thumbnailInputSrc = thumbnail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -88,10 +88,10 @@ class SelectThumbnail extends React.PureComponent<Props> {
|
||||||
<div>
|
<div>
|
||||||
{status === THUMBNAIL_STATUSES.API_DOWN || status === THUMBNAIL_STATUSES.MANUAL ? (
|
{status === THUMBNAIL_STATUSES.API_DOWN || status === THUMBNAIL_STATUSES.MANUAL ? (
|
||||||
<div className="column">
|
<div className="column">
|
||||||
<div className="column__item thumbnail-preview" style={{ backgroundImage: `url(${thumbnailSrc})` }}>
|
<div className="column__item thumbnail-preview" style={{ backgroundImage: `url(${thumbnailInputSrc})` }}>
|
||||||
<img
|
<img
|
||||||
style={{ display: 'none' }}
|
style={{ display: 'none' }}
|
||||||
src={thumbnailSrc}
|
src={thumbnailInputSrc}
|
||||||
alt={__('Thumbnail Preview')}
|
alt={__('Thumbnail Preview')}
|
||||||
onError={() => updatePublishForm({ thumbnailError: true })}
|
onError={() => updatePublishForm({ thumbnailError: true })}
|
||||||
/>
|
/>
|
||||||
|
@ -128,7 +128,16 @@ class SelectThumbnail extends React.PureComponent<Props> {
|
||||||
)}
|
)}
|
||||||
{status === THUMBNAIL_STATUSES.COMPLETE && thumbnail && (
|
{status === THUMBNAIL_STATUSES.COMPLETE && thumbnail && (
|
||||||
<div className="column column--space-between">
|
<div className="column column--space-between">
|
||||||
<div className="column__item thumbnail-preview" style={{ backgroundImage: `url(${thumbnail})` }} />
|
<div className="column__item thumbnail-preview" style={{ backgroundImage: `url(${thumbnail})` }}>
|
||||||
|
{(thumbnailError !== false) && __('This will be visible in a few minutes.')}
|
||||||
|
<img
|
||||||
|
style={{ display: 'none' }}
|
||||||
|
src={thumbnail}
|
||||||
|
alt={__('Thumbnail Preview')}
|
||||||
|
onError={() => updatePublishForm({ thumbnailError: true })}
|
||||||
|
onLoad={() => updatePublishForm({ thumbnailError: false })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div className="column__item">
|
<div className="column__item">
|
||||||
<p>{__('Upload complete.')}</p>
|
<p>{__('Upload complete.')}</p>
|
||||||
<div className="section__actions">
|
<div className="section__actions">
|
||||||
|
|
|
@ -4,17 +4,30 @@ import {
|
||||||
selectMyChannelUrls,
|
selectMyChannelUrls,
|
||||||
doFetchChannelListMine,
|
doFetchChannelListMine,
|
||||||
selectFetchingMyChannels,
|
selectFetchingMyChannels,
|
||||||
|
makeSelectClaimIsPending,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { doSetActiveChannel } from 'redux/actions/app';
|
import { doSetActiveChannel } from 'redux/actions/app';
|
||||||
import { selectYoutubeChannels } from 'redux/selectors/user';
|
import { selectYoutubeChannels } from 'redux/selectors/user';
|
||||||
import ChannelsPage from './view';
|
import ChannelsPage from './view';
|
||||||
|
|
||||||
const select = (state) => ({
|
const select = (state) => {
|
||||||
channelUrls: selectMyChannelUrls(state),
|
const channelUrls = selectMyChannelUrls(state);
|
||||||
channels: selectMyChannelClaims(state),
|
let pendingChannels = [];
|
||||||
fetchingChannels: selectFetchingMyChannels(state),
|
if (channelUrls) {
|
||||||
youtubeChannels: selectYoutubeChannels(state),
|
channelUrls.map((channelUrl) => {
|
||||||
});
|
const isPendingUrl = makeSelectClaimIsPending(channelUrl)(state);
|
||||||
|
if (isPendingUrl) pendingChannels.push(channelUrl);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
channelUrls,
|
||||||
|
channels: selectMyChannelClaims(state),
|
||||||
|
fetchingChannels: selectFetchingMyChannels(state),
|
||||||
|
youtubeChannels: selectYoutubeChannels(state),
|
||||||
|
pendingChannels,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const perform = (dispatch) => ({
|
const perform = (dispatch) => ({
|
||||||
fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
|
fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
|
||||||
|
|
|
@ -20,18 +20,26 @@ type Props = {
|
||||||
fetchingChannels: boolean,
|
fetchingChannels: boolean,
|
||||||
youtubeChannels: ?Array<any>,
|
youtubeChannels: ?Array<any>,
|
||||||
doSetActiveChannel: (string) => void,
|
doSetActiveChannel: (string) => void,
|
||||||
|
pendingChannels: Array<string>,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function ChannelsPage(props: Props) {
|
export default function ChannelsPage(props: Props) {
|
||||||
const { channels, channelUrls, fetchChannelListMine, fetchingChannels, youtubeChannels, doSetActiveChannel } = props;
|
const {
|
||||||
|
channelUrls,
|
||||||
|
fetchChannelListMine,
|
||||||
|
fetchingChannels,
|
||||||
|
youtubeChannels,
|
||||||
|
doSetActiveChannel,
|
||||||
|
pendingChannels,
|
||||||
|
} = props;
|
||||||
const [rewardData, setRewardData] = React.useState();
|
const [rewardData, setRewardData] = React.useState();
|
||||||
const hasYoutubeChannels = youtubeChannels && Boolean(youtubeChannels.length);
|
const hasYoutubeChannels = youtubeChannels && Boolean(youtubeChannels.length);
|
||||||
const hasPendingChannels = channels && channels.some((channel) => channel.confirmations < 0);
|
|
||||||
const { push } = useHistory();
|
const { push } = useHistory();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchChannelListMine();
|
fetchChannelListMine();
|
||||||
}, [fetchChannelListMine, hasPendingChannels]);
|
}, [fetchChannelListMine]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Lbryio.call('user_rewards', 'view_rate').then((data) => setRewardData(data));
|
Lbryio.call('user_rewards', 'view_rate').then((data) => setRewardData(data));
|
||||||
|
@ -86,7 +94,7 @@ export default function ChannelsPage(props: Props) {
|
||||||
return data.channel_claim_id === claim.claim_id;
|
return data.channel_claim_id === claim.claim_id;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (channelRewardData) {
|
if (channelRewardData && !pendingChannels.includes(claim.permanent_url)) {
|
||||||
return (
|
return (
|
||||||
<span className="claim-preview__custom-properties">
|
<span className="claim-preview__custom-properties">
|
||||||
<span className="help--inline">
|
<span className="help--inline">
|
||||||
|
|
Loading…
Reference in a new issue