Outstanding routing cleanup #2405
26 changed files with 252 additions and 301 deletions
3
flow-typed/web.js
vendored
Normal file
3
flow-typed/web.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
// @flow
|
||||
|
||||
declare var IS_WEB: boolean;
|
|
@ -70,14 +70,14 @@ class App extends React.PureComponent<Props> {
|
|||
return (
|
||||
<div id="window" onContextMenu={e => openContextMenu(e)}>
|
||||
<Header />
|
||||
<main className="page">
|
||||
<section className="page">
|
||||
{enhancedLayout && <Yrbl className="yrbl--enhanced" />}
|
||||
|
||||
<SideBar />
|
||||
<div className="content" id="content">
|
||||
<Router />
|
||||
<ModalRouter />
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
|
||||
const LbcSymbol = () => <span> LBC</span>; // ℄
|
||||
const LbcSymbol = () => <span>LBC</span>; // ℄
|
||||
|
||||
export default LbcSymbol;
|
||||
|
|
|
@ -202,8 +202,8 @@ class MediaPlayer extends React.PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
// @if TARGET='app'
|
||||
sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
sleep(ms: number) {
|
||||
return new Promise<void>(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
refreshMetadata() {
|
||||
|
|
|
@ -47,6 +47,7 @@ type Props = {
|
|||
nextFileToPlay: ?string,
|
||||
navigate: (string, {}) => void,
|
||||
costInfo: ?{ cost: number },
|
||||
insufficientCredits: boolean,
|
||||
};
|
||||
|
||||
class FileViewer extends React.PureComponent<Props> {
|
||||
|
@ -150,7 +151,11 @@ class FileViewer extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
playContent() {
|
||||
const { play, uri, fileInfo, isDownloading, isLoading } = this.props;
|
||||
const { play, uri, fileInfo, isDownloading, isLoading, insufficientCredits } = this.props;
|
||||
|
||||
if (insufficientCredits) {
|
||||
return;
|
||||
}
|
||||
|
||||
// @if TARGET='app'
|
||||
if (fileInfo || isDownloading || isLoading) {
|
||||
|
@ -220,6 +225,7 @@ class FileViewer extends React.PureComponent<Props> {
|
|||
className,
|
||||
obscureNsfw,
|
||||
mediaType,
|
||||
insufficientCredits,
|
||||
} = this.props;
|
||||
|
||||
const isPlaying = playingUri === uri;
|
||||
|
@ -246,7 +252,10 @@ class FileViewer extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
const poster = metadata && metadata.thumbnail;
|
||||
const layoverClass = classnames('content__cover', { 'card__media--nsfw': shouldObscureNsfw });
|
||||
const layoverClass = classnames('content__cover', {
|
||||
'card__media--nsfw': shouldObscureNsfw,
|
||||
'card__media--disabled': insufficientCredits,
|
||||
});
|
||||
|
||||
const layoverStyle =
|
||||
!shouldObscureNsfw && poster ? { backgroundImage: `url("${poster}")` } : {};
|
||||
|
|
|
@ -85,8 +85,7 @@ const Header = (props: Props) => {
|
|||
title={`Your balance is ${balance} LBRY Credits`}
|
||||
label={
|
||||
<React.Fragment>
|
||||
<span>{roundedBalance}</span>
|
||||
<LbcSymbol />
|
||||
{roundedBalance} <LbcSymbol />
|
||||
</React.Fragment>
|
||||
}
|
||||
navigate="/$/wallet"
|
||||
|
@ -94,6 +93,7 @@ const Header = (props: Props) => {
|
|||
|
||||
<Button
|
||||
className="header__navigation-item header__navigation-item--right-action"
|
||||
activeClass="header__navigation-item--active"
|
||||
description={__('Publish content')}
|
||||
icon={ICONS.UPLOAD}
|
||||
iconSize={24}
|
||||
|
|
|
@ -332,6 +332,7 @@ class PublishForm extends React.PureComponent<Props> {
|
|||
resetThumbnailStatus,
|
||||
isStillEditing,
|
||||
amountNeededForTakeover,
|
||||
balance,
|
||||
} = this.props;
|
||||
|
||||
const formDisabled = (!filePath && !editingURI) || publishing;
|
||||
|
@ -352,7 +353,7 @@ class PublishForm extends React.PureComponent<Props> {
|
|||
<Form onSubmit={this.handlePublish}>
|
||||
<section
|
||||
className={classnames('card card--section', {
|
||||
'card--disabled': IS_WEB || publishing,
|
||||
'card--disabled': IS_WEB || publishing || balance === 0,
|
||||
})}
|
||||
>
|
||||
<header className="card__header">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as PAGES from 'constants/pages';
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { Router } from '@reach/router';
|
||||
import SettingsPage from 'page/settings';
|
||||
import HelpPage from 'page/help';
|
||||
|
@ -21,31 +21,47 @@ import UserHistoryPage from 'page/userHistory';
|
|||
import SendCreditsPage from 'page/sendCredits';
|
||||
import NavigationHistory from 'page/navigationHistory';
|
||||
|
||||
export default function AppRouter(props) {
|
||||
const ScrollHandler = props => {
|
||||
const { key } = props.location;
|
||||
|
||||
useEffect(() => {
|
||||
// This shouldn't scroll to top when you click "back"
|
||||
// Might take some more work but fixes scroll position being stuck on navigation for now
|
||||
const main = document.querySelector('main');
|
||||
main.scrollIntoView();
|
||||
}, [key]);
|
||||
|
||||
return props.children;
|
||||
};
|
||||
|
||||
export default function AppRouter() {
|
||||
return (
|
||||
<Router>
|
||||
<DiscoverPage path="/" />
|
||||
<ShowPage path="/:claimName/:claimId" />
|
||||
<ShowPage path="/:claimName" />
|
||||
<ScrollHandler path="/">
|
||||
<DiscoverPage path="/" />
|
||||
<ShowPage path="/:claimName/:claimId" />
|
||||
<ShowPage path="/:claimName" />
|
||||
{/* <ShowPage path="/" uri="five" /> */}
|
||||
|
||||
<AuthPage path={`$/${PAGES.AUTH}`} />
|
||||
<BackupPage path={`$/${PAGES.BACKUP}`} />
|
||||
<InvitePage path={`$/${PAGES.INVITE}`} />
|
||||
<FileListDownloaded path={`$/${PAGES.DOWNLOADED}`} />
|
||||
<FileListPublished path={`$/${PAGES.PUBLISHED}`} />
|
||||
<HelpPage path={`$/${PAGES.HELP}`} />
|
||||
<PublishPage path={`$/${PAGES.PUBLISH}`} />
|
||||
<ReportPage path={`$/${PAGES.REPORT}`} />
|
||||
<RewardsPage path={`$/${PAGES.REWARDS}`} />
|
||||
<SearchPage path={`$/${PAGES.SEARCH}`} />
|
||||
<SettingsPage path={`$/${PAGES.SETTINGS}`} />
|
||||
<SubscriptionsPage path={`$/${PAGES.SUBSCRIPTIONS}`} />
|
||||
<TransactionHistoryPage path={`$/${PAGES.TRANSACTIONS}`} />
|
||||
<UserHistoryPage path={`$/${PAGES.HISTORY}`} />
|
||||
<AccountPage path={`$/${PAGES.ACCOUNT}`} />
|
||||
<SendCreditsPage path={`$/${PAGES.SEND}`} />
|
||||
<UserHistoryPage path={`$/${PAGES.HISTORY}`} />
|
||||
<NavigationHistory path={`$/${PAGES.HISTORY}/all`} />
|
||||
<AuthPage path={`$/${PAGES.AUTH}`} />
|
||||
<BackupPage path={`$/${PAGES.BACKUP}`} />
|
||||
<InvitePage path={`$/${PAGES.INVITE}`} />
|
||||
<FileListDownloaded path={`$/${PAGES.DOWNLOADED}`} />
|
||||
<FileListPublished path={`$/${PAGES.PUBLISHED}`} />
|
||||
<HelpPage path={`$/${PAGES.HELP}`} />
|
||||
<PublishPage path={`$/${PAGES.PUBLISH}`} />
|
||||
<ReportPage path={`$/${PAGES.REPORT}`} />
|
||||
<RewardsPage path={`$/${PAGES.REWARDS}`} />
|
||||
<SearchPage path={`$/${PAGES.SEARCH}`} />
|
||||
<SettingsPage path={`$/${PAGES.SETTINGS}`} />
|
||||
<SubscriptionsPage path={`$/${PAGES.SUBSCRIPTIONS}`} />
|
||||
<TransactionHistoryPage path={`$/${PAGES.TRANSACTIONS}`} />
|
||||
<UserHistoryPage path={`$/${PAGES.HISTORY}`} />
|
||||
<AccountPage path={`$/${PAGES.ACCOUNT}`} />
|
||||
<SendCreditsPage path={`$/${PAGES.SEND}`} />
|
||||
<UserHistoryPage path={`$/${PAGES.HISTORY}`} />
|
||||
<NavigationHistory path={`$/${PAGES.HISTORY}/all`} />
|
||||
</ScrollHandler>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -27,12 +27,12 @@ export default class extends React.PureComponent<Props> {
|
|||
const image = yrblTypes[type];
|
||||
|
||||
return (
|
||||
<div className="yrbl-wrap">
|
||||
<img alt="Friendly gerbil" className={classnames('yrbl', className)} src={image} />
|
||||
<div className="yrbl__wrap">
|
||||
<img alt="Friendly gerbil" className={classnames('yrbl', className)} src={`/${image}`} />
|
||||
{title && subtitle && (
|
||||
<div className="card__content">
|
||||
<div className="yrbl__content">
|
||||
<h2 className="card__title">{title}</h2>
|
||||
<div className="card__subtitle">{subtitle}</div>
|
||||
<div className="card__content">{subtitle}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,6 @@ export const DOWNLOADING = 'downloading';
|
|||
export const AUTO_UPDATE_DOWNLOADED = 'auto_update_downloaded';
|
||||
export const AUTO_UPDATE_CONFIRM = 'auto_update_confirm';
|
||||
export const ERROR = 'error';
|
||||
export const INSUFFICIENT_CREDITS = 'insufficient_credits';
|
||||
export const UPGRADE = 'upgrade';
|
||||
export const WELCOME = 'welcome';
|
||||
export const EMAIL_COLLECTION = 'email_collection';
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doSetClientSetting } from 'redux/actions/settings';
|
||||
import { selectUserIsRewardApproved, selectUnclaimedRewardValue } from 'lbryinc';
|
||||
import { selectBalance } from 'lbry-redux';
|
||||
import { doHideModal } from 'redux/actions/app';
|
||||
import * as settings from 'constants/settings';
|
||||
import ModalCreditIntro from './view';
|
||||
import { navigate } from '@reach/router';
|
||||
|
||||
const select = state => ({
|
||||
currentBalance: selectBalance(state),
|
||||
isRewardApproved: selectUserIsRewardApproved(state),
|
||||
totalRewardValue: selectUnclaimedRewardValue(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => () => ({
|
||||
addBalance: () => {
|
||||
navigate('/$/getcredits');
|
||||
dispatch(doSetClientSetting(settings.CREDIT_REQUIRED_ACKNOWLEDGED, true));
|
||||
dispatch(doHideModal());
|
||||
},
|
||||
closeModal: () => {
|
||||
dispatch(doSetClientSetting(settings.CREDIT_REQUIRED_ACKNOWLEDGED, true));
|
||||
dispatch(doHideModal());
|
||||
},
|
||||
});
|
||||
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
)(ModalCreditIntro);
|
|
@ -1,56 +0,0 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import { Modal } from 'modal/modal';
|
||||
import CurrencySymbol from 'component/common/lbc-symbol';
|
||||
import CreditAmount from 'component/common/credit-amount';
|
||||
import Button from 'component/button';
|
||||
|
||||
type Props = {
|
||||
totalRewardValue: number,
|
||||
currentBalance: number,
|
||||
closeModal: () => void,
|
||||
addBalance: () => void,
|
||||
};
|
||||
|
||||
const ModalCreditIntro = (props: Props) => {
|
||||
const { closeModal, totalRewardValue, currentBalance, addBalance } = props;
|
||||
const totalRewardRounded = Math.floor(totalRewardValue / 10) * 10;
|
||||
|
||||
return (
|
||||
<Modal type="custom" isOpen contentLabel="Welcome to LBRY" title={__('LBRY Credits Needed')}>
|
||||
<section className="card__content">
|
||||
<p>
|
||||
Some actions require LBRY credits (
|
||||
<em>
|
||||
<CurrencySymbol />
|
||||
</em>
|
||||
), the blockchain token that powers the LBRY network.
|
||||
</p>
|
||||
{currentBalance <= 0 && (
|
||||
<p>
|
||||
You currently have <CreditAmount inheritStyle amount={currentBalance} />, so the actions
|
||||
you can take are limited.
|
||||
</p>
|
||||
)}
|
||||
{Boolean(totalRewardValue) && (
|
||||
<p>
|
||||
{__(' There are a variety of ways to get credits, including more than')}{' '}
|
||||
<CreditAmount inheritStyle amount={totalRewardRounded} />{' '}
|
||||
{__('in free rewards for participating in the LBRY beta.')}
|
||||
</p>
|
||||
)}
|
||||
</section>
|
||||
|
||||
<div className="card__actions">
|
||||
<Button button="primary" onClick={addBalance} label={__('Get Credits')} />
|
||||
<Button
|
||||
button="link"
|
||||
onClick={closeModal}
|
||||
label={currentBalance <= 0 ? __('Use Without LBC') : __('Meh, Not Now')}
|
||||
/>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModalCreditIntro;
|
|
@ -1,28 +1,15 @@
|
|||
import { connect } from 'react-redux';
|
||||
import * as settings from 'constants/settings';
|
||||
import { selectBalance, makeSelectCostInfoForUri, selectError, doToast } from 'lbry-redux';
|
||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
import { selectUser, selectUserIsVerificationCandidate } from 'lbryinc';
|
||||
import { selectModal } from 'redux/selectors/app';
|
||||
import { doOpenModal } from 'redux/actions/app';
|
||||
import { selectError } from 'lbry-redux';
|
||||
import ModalRouter from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
balance: selectBalance(state),
|
||||
showPageCost: makeSelectCostInfoForUri(props.uri)(state),
|
||||
isVerificationCandidate: selectUserIsVerificationCandidate(state),
|
||||
isCreditIntroAcknowledged: makeSelectClientSetting(settings.CREDIT_REQUIRED_ACKNOWLEDGED)(state),
|
||||
isEmailCollectionAcknowledged: makeSelectClientSetting(settings.EMAIL_COLLECTION_ACKNOWLEDGED)(
|
||||
state
|
||||
),
|
||||
isWelcomeAcknowledged: makeSelectClientSetting(settings.NEW_USER_ACKNOWLEDGED)(state),
|
||||
user: selectUser(state),
|
||||
modal: selectModal(state),
|
||||
error: selectError(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
showToast: props => dispatch(doToast(props)),
|
||||
openModal: props => dispatch(doOpenModal(props)),
|
||||
});
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import ModalUpgrade from 'modal/modalUpgrade';
|
|||
import ModalWelcome from 'modal/modalWelcome';
|
||||
import ModalFirstReward from 'modal/modalFirstReward';
|
||||
import ModalRewardApprovalRequired from 'modal/modalRewardApprovalRequired';
|
||||
import ModalCreditIntro from 'modal/modalCreditIntro';
|
||||
import ModalRemoveFile from 'modal/modalRemoveFile';
|
||||
import ModalTransactionFailed from 'modal/modalTransactionFailed';
|
||||
import ModalFileTimeout from 'modal/modalFileTimeout';
|
||||
|
@ -32,162 +31,76 @@ import ModalRewardCode from 'modal/modalRewardCode';
|
|||
type Props = {
|
||||
modal: { id: string, modalProps: {} },
|
||||
error: { message: string },
|
||||
openModal: string => void,
|
||||
page: string,
|
||||
isWelcomeAcknowledged: boolean,
|
||||
isEmailCollectionAcknowledged: boolean,
|
||||
isVerificationCandidate: boolean,
|
||||
isCreditIntroAcknowledged: boolean,
|
||||
balance: number,
|
||||
showPageCost: number,
|
||||
user: {
|
||||
is_reward_approved: boolean,
|
||||
is_identity_verified: boolean,
|
||||
has_verified_email: boolean,
|
||||
},
|
||||
};
|
||||
|
||||
type State = {
|
||||
lastTransitionModal: ?string,
|
||||
lastTransitionPage: ?string,
|
||||
};
|
||||
function ModalRouter(props: Props) {
|
||||
const { modal, error } = props;
|
||||
|
||||
class ModalRouter extends React.PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
lastTransitionModal: null,
|
||||
lastTransitionPage: null,
|
||||
};
|
||||
if (error) {
|
||||
return <ModalError {...error} />;
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.showTransitionModals(this.props);
|
||||
if (!modal) {
|
||||
return null;
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: Props) {
|
||||
this.showTransitionModals(nextProps);
|
||||
}
|
||||
const { id, modalProps } = modal;
|
||||
|
||||
showTransitionModals(props: Props) {
|
||||
const { modal, openModal, page } = props;
|
||||
|
||||
if (modal) {
|
||||
return;
|
||||
}
|
||||
|
||||
const transitionModal = [this.checkShowCreditIntro].reduce(
|
||||
(acc, func) => (!acc ? func.bind(this)(props) : acc),
|
||||
false
|
||||
);
|
||||
|
||||
if (
|
||||
transitionModal &&
|
||||
(transitionModal !== this.state.lastTransitionModal || page !== this.state.lastTransitionPage)
|
||||
) {
|
||||
openModal(transitionModal);
|
||||
this.setState({
|
||||
lastTransitionModal: transitionModal,
|
||||
lastTransitionPage: page,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
checkShowCreditIntro(props: Props) {
|
||||
// @if TARGET='app'
|
||||
// This doesn't make sense to show until the web has wallet support
|
||||
const { balance, page, isCreditIntroAcknowledged } = props;
|
||||
|
||||
if (
|
||||
balance === 0 &&
|
||||
!isCreditIntroAcknowledged &&
|
||||
(['send', 'publish'].includes(page) || this.isPaidShowPage(props))
|
||||
) {
|
||||
return MODALS.INSUFFICIENT_CREDITS;
|
||||
}
|
||||
// @endif
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
isPaidShowPage(props: Props) {
|
||||
const { page, showPageCost } = props;
|
||||
// Fix me
|
||||
return page === 'show' && showPageCost > 0;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { modal, error } = this.props;
|
||||
|
||||
if (error) {
|
||||
return <ModalError {...error} />;
|
||||
}
|
||||
|
||||
if (!modal) {
|
||||
switch (id) {
|
||||
case MODALS.UPGRADE:
|
||||
return <ModalUpgrade {...modalProps} />;
|
||||
case MODALS.DOWNLOADING:
|
||||
return <ModalDownloading {...modalProps} />;
|
||||
case MODALS.AUTO_UPDATE_DOWNLOADED:
|
||||
return <ModalAutoUpdateDownloaded {...modalProps} />;
|
||||
case MODALS.AUTO_UPDATE_CONFIRM:
|
||||
return <ModalAutoUpdateConfirm {...modalProps} />;
|
||||
case MODALS.ERROR:
|
||||
return <ModalError {...modalProps} />;
|
||||
case MODALS.FILE_TIMEOUT:
|
||||
return <ModalFileTimeout {...modalProps} />;
|
||||
case MODALS.WELCOME:
|
||||
return <ModalWelcome {...modalProps} />;
|
||||
case MODALS.FIRST_REWARD:
|
||||
return <ModalFirstReward {...modalProps} />;
|
||||
case MODALS.AUTHENTICATION_FAILURE:
|
||||
return <ModalAuthFailure {...modalProps} />;
|
||||
case MODALS.TRANSACTION_FAILED:
|
||||
return <ModalTransactionFailed {...modalProps} />;
|
||||
case MODALS.REWARD_APPROVAL_REQUIRED:
|
||||
return <ModalRewardApprovalRequired {...modalProps} />;
|
||||
case MODALS.CONFIRM_FILE_REMOVE:
|
||||
return <ModalRemoveFile {...modalProps} />;
|
||||
case MODALS.AFFIRM_PURCHASE:
|
||||
return <ModalAffirmPurchase {...modalProps} />;
|
||||
case MODALS.CONFIRM_CLAIM_REVOKE:
|
||||
return <ModalRevokeClaim {...modalProps} />;
|
||||
case MODALS.PHONE_COLLECTION:
|
||||
return <ModalPhoneCollection {...modalProps} />;
|
||||
case MODALS.FIRST_SUBSCRIPTION:
|
||||
return <ModalFirstSubscription {...modalProps} />;
|
||||
case MODALS.SEND_TIP:
|
||||
return <ModalSendTip {...modalProps} />;
|
||||
case MODALS.SOCIAL_SHARE:
|
||||
return <ModalSocialShare {...modalProps} />;
|
||||
case MODALS.PUBLISH:
|
||||
return <ModalPublish {...modalProps} />;
|
||||
case MODALS.CONFIRM_EXTERNAL_LINK:
|
||||
return <ModalOpenExternalLink {...modalProps} />;
|
||||
case MODALS.CONFIRM_TRANSACTION:
|
||||
return <ModalConfirmTransaction {...modalProps} />;
|
||||
case MODALS.CONFIRM_THUMBNAIL_UPLOAD:
|
||||
return <ModalConfirmThumbnailUpload {...modalProps} />;
|
||||
case MODALS.WALLET_ENCRYPT:
|
||||
return <ModalWalletEncrypt {...modalProps} />;
|
||||
case MODALS.WALLET_DECRYPT:
|
||||
return <ModalWalletDecrypt {...modalProps} />;
|
||||
case MODALS.WALLET_UNLOCK:
|
||||
return <ModalWalletUnlock {...modalProps} />;
|
||||
case MODALS.REWARD_GENERATED_CODE:
|
||||
return <ModalRewardCode {...modalProps} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
const { id, modalProps } = modal;
|
||||
|
||||
switch (id) {
|
||||
case MODALS.UPGRADE:
|
||||
return <ModalUpgrade {...modalProps} />;
|
||||
case MODALS.DOWNLOADING:
|
||||
return <ModalDownloading {...modalProps} />;
|
||||
case MODALS.AUTO_UPDATE_DOWNLOADED:
|
||||
return <ModalAutoUpdateDownloaded {...modalProps} />;
|
||||
case MODALS.AUTO_UPDATE_CONFIRM:
|
||||
return <ModalAutoUpdateConfirm {...modalProps} />;
|
||||
case MODALS.ERROR:
|
||||
return <ModalError {...modalProps} />;
|
||||
case MODALS.FILE_TIMEOUT:
|
||||
return <ModalFileTimeout {...modalProps} />;
|
||||
case MODALS.INSUFFICIENT_CREDITS:
|
||||
return <ModalCreditIntro {...modalProps} />;
|
||||
case MODALS.WELCOME:
|
||||
return <ModalWelcome {...modalProps} />;
|
||||
case MODALS.FIRST_REWARD:
|
||||
return <ModalFirstReward {...modalProps} />;
|
||||
case MODALS.AUTHENTICATION_FAILURE:
|
||||
return <ModalAuthFailure {...modalProps} />;
|
||||
case MODALS.TRANSACTION_FAILED:
|
||||
return <ModalTransactionFailed {...modalProps} />;
|
||||
case MODALS.REWARD_APPROVAL_REQUIRED:
|
||||
return <ModalRewardApprovalRequired {...modalProps} />;
|
||||
case MODALS.CONFIRM_FILE_REMOVE:
|
||||
return <ModalRemoveFile {...modalProps} />;
|
||||
case MODALS.AFFIRM_PURCHASE:
|
||||
return <ModalAffirmPurchase {...modalProps} />;
|
||||
case MODALS.CONFIRM_CLAIM_REVOKE:
|
||||
return <ModalRevokeClaim {...modalProps} />;
|
||||
case MODALS.PHONE_COLLECTION:
|
||||
return <ModalPhoneCollection {...modalProps} />;
|
||||
case MODALS.FIRST_SUBSCRIPTION:
|
||||
return <ModalFirstSubscription {...modalProps} />;
|
||||
case MODALS.SEND_TIP:
|
||||
return <ModalSendTip {...modalProps} />;
|
||||
case MODALS.SOCIAL_SHARE:
|
||||
return <ModalSocialShare {...modalProps} />;
|
||||
case MODALS.PUBLISH:
|
||||
return <ModalPublish {...modalProps} />;
|
||||
case MODALS.CONFIRM_EXTERNAL_LINK:
|
||||
return <ModalOpenExternalLink {...modalProps} />;
|
||||
case MODALS.CONFIRM_TRANSACTION:
|
||||
return <ModalConfirmTransaction {...modalProps} />;
|
||||
case MODALS.CONFIRM_THUMBNAIL_UPLOAD:
|
||||
return <ModalConfirmThumbnailUpload {...modalProps} />;
|
||||
case MODALS.WALLET_ENCRYPT:
|
||||
return <ModalWalletEncrypt {...modalProps} />;
|
||||
case MODALS.WALLET_DECRYPT:
|
||||
return <ModalWalletDecrypt {...modalProps} />;
|
||||
case MODALS.WALLET_UNLOCK:
|
||||
return <ModalWalletUnlock {...modalProps} />;
|
||||
case MODALS.REWARD_GENERATED_CODE:
|
||||
return <ModalRewardCode {...modalProps} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
makeSelectContentTypeForUri,
|
||||
makeSelectMetadataForUri,
|
||||
makeSelectChannelForClaimUri,
|
||||
selectBalance,
|
||||
} from 'lbry-redux';
|
||||
import {
|
||||
doFetchViewCount,
|
||||
|
@ -39,6 +40,7 @@ const select = (state, props) => ({
|
|||
isSubscribed: makeSelectIsSubscribed(props.uri)(state),
|
||||
channelUri: makeSelectChannelForClaimUri(props.uri, true)(state),
|
||||
viewCount: makeSelectViewCountForUri(props.uri)(state),
|
||||
balance: selectBalance(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
|
|
|
@ -42,6 +42,7 @@ type Props = {
|
|||
openModal: (id: string, { uri: string }) => void,
|
||||
markSubscriptionRead: (string, string) => void,
|
||||
fetchViewCount: string => void,
|
||||
balance: number,
|
||||
};
|
||||
|
||||
class FilePage extends React.Component<Props> {
|
||||
|
@ -135,6 +136,7 @@ class FilePage extends React.Component<Props> {
|
|||
fileInfo,
|
||||
channelUri,
|
||||
viewCount,
|
||||
balance,
|
||||
} = this.props;
|
||||
|
||||
// File info
|
||||
|
@ -147,6 +149,7 @@ class FilePage extends React.Component<Props> {
|
|||
const mediaType = getMediaType(contentType, fileName);
|
||||
const showFile =
|
||||
PLAYABLE_MEDIA_TYPES.includes(mediaType) || PREVIEW_MEDIA_TYPES.includes(mediaType);
|
||||
|
||||
const speechShareable =
|
||||
costInfo &&
|
||||
costInfo.cost === 0 &&
|
||||
|
@ -168,11 +171,32 @@ class FilePage extends React.Component<Props> {
|
|||
editUri = buildURI(uriObject);
|
||||
}
|
||||
|
||||
const insufficientCredits = costInfo && costInfo.cost > balance;
|
||||
|
||||
return (
|
||||
<Page notContained className="main--file-page">
|
||||
<div className="grid-area--content">
|
||||
<h1 className="media__uri">{uri}</h1>
|
||||
{showFile && <FileViewer className="content__embedded" uri={uri} mediaType={mediaType} />}
|
||||
<h1 className="media__uri">
|
||||
<Button navigate={uri} label={uri} />
|
||||
</h1>
|
||||
{insufficientCredits && (
|
||||
<div className="media__insufficient-credits help--warning">
|
||||
{__(
|
||||
'The publisher has chosen to charge LBC to view this content. Your balance is currently to low to view it.'
|
||||
)}{' '}
|
||||
{__('Checkout')}{' '}
|
||||
<Button button="link" navigate="/$/rewards" label={__('the rewards page')} />{' '}
|
||||
{__('or send more LBC to your wallet.')}
|
||||
</div>
|
||||
)}
|
||||
{showFile && (
|
||||
<FileViewer
|
||||
insufficientCredits={insufficientCredits}
|
||||
className="content__embedded"
|
||||
uri={uri}
|
||||
mediaType={mediaType}
|
||||
/>
|
||||
)}
|
||||
{!showFile &&
|
||||
(thumbnail ? (
|
||||
<Thumbnail shouldObscure={shouldObscureThumbnail} src={thumbnail} />
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
doPublish,
|
||||
doPrepareEdit,
|
||||
} from 'redux/actions/publish';
|
||||
import { selectUnclaimedRewardValue } from 'lbryinc';
|
||||
import PublishPage from './view';
|
||||
|
||||
const select = state => ({
|
||||
|
@ -27,6 +28,7 @@ const select = state => ({
|
|||
isStillEditing: selectIsStillEditing(state),
|
||||
balance: selectBalance(state),
|
||||
isResolvingUri: selectIsResolvingPublishUris(state),
|
||||
totalRewardValue: selectUnclaimedRewardValue(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
|
|
|
@ -1,19 +1,65 @@
|
|||
import React from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
import PublishForm from 'component/publishForm';
|
||||
import Page from 'component/page';
|
||||
import Yrbl from 'component/yrbl';
|
||||
import LbcSymbol from 'component/common/lbc-symbol';
|
||||
import CreditAmount from 'component/common/credit-amount';
|
||||
import Button from 'component/button';
|
||||
|
||||
class PublishPage extends React.PureComponent {
|
||||
scrollToTop = () => {
|
||||
// #content wraps every <Page>
|
||||
const mainContent = document.getElementById('content');
|
||||
const mainContent = document.querySelector('main');
|
||||
if (mainContent) {
|
||||
mainContent.scrollTop = 0; // It would be nice to animate this
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { balance, totalRewardValue } = this.props;
|
||||
const totalRewardRounded = Math.floor(totalRewardValue / 10) * 10;
|
||||
|
||||
return (
|
||||
<Page>
|
||||
{balance === 0 && (
|
||||
<Fragment>
|
||||
<Yrbl
|
||||
title={__("You can't publish things quite yet")}
|
||||
subtitle={
|
||||
<Fragment>
|
||||
<p>
|
||||
{__(
|
||||
'LBRY uses a blockchain, which is a fancy way of saying that users (you) are in control of your data.'
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
{__('Because of the blockchain, some actions require LBRY credits')} (
|
||||
<LbcSymbol />
|
||||
).
|
||||
</p>
|
||||
<p>
|
||||
<LbcSymbol />{' '}
|
||||
{__(
|
||||
'allows you to do some neat things, like paying your favorite creators for their content. And no company can stop you.'
|
||||
)}
|
||||
</p>
|
||||
</Fragment>
|
||||
}
|
||||
/>
|
||||
<section className="card card--section">
|
||||
<header className="card__header">
|
||||
<h1 className="card__title">{__('LBRY Credits Required')}</h1>
|
||||
</header>
|
||||
<p className="card__subtitle">
|
||||
{__(' There are a variety of ways to get credits, including more than')}{' '}
|
||||
<CreditAmount inheritStyle amount={totalRewardRounded} />{' '}
|
||||
{__('in free rewards for participating in the LBRY beta.')}
|
||||
</p>
|
||||
<div className="card__actions">
|
||||
<Button button="link" navigate="/$/rewards" label={__('Checkout the rewards')} />
|
||||
</div>
|
||||
</section>
|
||||
</Fragment>
|
||||
)}
|
||||
<PublishForm {...this.props} scrollToTop={this.scrollToTop} />
|
||||
</Page>
|
||||
);
|
||||
|
|
|
@ -272,7 +272,6 @@ export function doPurchaseUri(
|
|||
|
||||
if (cost > balance) {
|
||||
dispatch(doSetPlayingUri(null));
|
||||
dispatch(doOpenModal(MODALS.INSUFFICIENT_CREDITS));
|
||||
Promise.resolve();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
.card {
|
||||
background-color: $lbry-white;
|
||||
border: 1px solid $lbry-gray-1;
|
||||
margin-bottom: var(--spacing-vertical-large);
|
||||
margin-bottom: var(--spacing-vertical-xlarge);
|
||||
position: relative;
|
||||
|
||||
html[data-mode='dark'] & {
|
||||
|
@ -84,6 +84,11 @@
|
|||
p:not(:last-child) {
|
||||
margin-bottom: var(--spacing-vertical-medium);
|
||||
}
|
||||
|
||||
.badge {
|
||||
bottom: -0.15rem;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
// C A R D
|
||||
|
@ -92,10 +97,6 @@
|
|||
.card__header {
|
||||
position: relative;
|
||||
|
||||
+ .card__content {
|
||||
margin-top: var(--spacing-vertical-medium);
|
||||
}
|
||||
|
||||
&:not(.card__header--flat) {
|
||||
margin-bottom: var(--spacing-vertical-small);
|
||||
}
|
||||
|
@ -195,6 +196,10 @@
|
|||
.button {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
+ .card__content {
|
||||
margin-top: var(--spacing-vertical-medium);
|
||||
}
|
||||
}
|
||||
|
||||
.card__title--flex {
|
||||
|
|
|
@ -67,6 +67,11 @@
|
|||
background-color: $lbry-grape-3;
|
||||
}
|
||||
|
||||
.card__media--disabled {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.content__loading {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
|
|
@ -81,6 +81,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
.header__navigation-item--active {
|
||||
background-image: linear-gradient(
|
||||
to bottom,
|
||||
transparent 0%,
|
||||
mix(transparent, $lbry-teal-3, 70%) 90%
|
||||
);
|
||||
}
|
||||
|
||||
.header__navigation-item--back,
|
||||
.header__navigation-item--forward,
|
||||
.header__navigation-item--home,
|
||||
|
|
|
@ -10,6 +10,16 @@
|
|||
.media__properties {
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 50px rgba($lbry-black, 0.08);
|
||||
background-color: rgba($lbry-black, 0.04);
|
||||
|
||||
html[data-mode='dark'] & {
|
||||
box-shadow: 0 0 50px rgba($lbry-white, 0.07);
|
||||
background-color: rgba($lbry-white, 0.03);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// M E D I A
|
||||
|
@ -145,6 +155,10 @@
|
|||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.media__insufficient-credits {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
// M E D I A
|
||||
// A C T I O N S
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.yrbl-wrap {
|
||||
.yrbl__wrap {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
vertical-align: middle;
|
||||
text-align: left;
|
||||
margin-bottom: var(--spacing-vertical-large);
|
||||
margin-bottom: var(--spacing-vertical-xlarge);
|
||||
}
|
||||
|
||||
.yrbl {
|
||||
|
@ -12,6 +12,10 @@
|
|||
margin-right: var(--spacing-vertical-large);
|
||||
}
|
||||
|
||||
.yrbl__content {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.yrbl--first-run {
|
||||
align-self: center;
|
||||
height: 250px;
|
||||
|
|
|
@ -170,7 +170,7 @@ code {
|
|||
}
|
||||
|
||||
html[data-mode='dark'] & {
|
||||
background-color: $lbry-yellow-4;
|
||||
background-color: $lbry-yellow-3;
|
||||
color: $lbry-black;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ $large-breakpoint: 1921px;
|
|||
--spacing-vertical-small: calc(2rem / 3);
|
||||
--spacing-vertical-medium: calc(2rem / 2);
|
||||
--spacing-vertical-large: 2rem;
|
||||
--spacing-vertical-xlarge: 3rem;
|
||||
|
||||
--file-page-max-width: 1787px;
|
||||
--file-max-height: 788px;
|
||||
|
|
Loading…
Reference in a new issue
The
<Page>
component contained<main>
too. It makes more sense to keep there.