diff --git a/.eslintrc.json b/.eslintrc.json index 023edb1c9..4d5958b53 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -29,6 +29,7 @@ "jsx-quotes": ["error", "prefer-double"], "new-cap": 0, "no-console": 1, + "no-control-regex": 0, "no-multi-spaces": 0, "no-redeclare": 0, "no-return-await": 0, @@ -38,11 +39,14 @@ "react/jsx-indent": 0, "react-hooks/exhaustive-deps": "warn", "react-hooks/rules-of-hooks": "error", - "space-before-function-paren": ["error", { - "anonymous": "never", - "named": "never", - "asyncArrow": "always" - }], + "space-before-function-paren": [ + "error", + { + "anonymous": "never", + "named": "never", + "asyncArrow": "always" + } + ], "standard/object-curly-even-spacing": 0, "standard/no-callback-literal": 0, "react/display-name": 0, diff --git a/.flowconfig b/.flowconfig index 24be028e1..de74dca59 100644 --- a/.flowconfig +++ b/.flowconfig @@ -5,6 +5,7 @@ [libs] ./flow-typed node_modules/lbry-redux/flow-typed/ +node_modules/lbryinc/flow-typed/ [lints] diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..80143ac0a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM node:10 +EXPOSE 1337 + +RUN yarn -v && npm -v +RUN apt-get update -y && apt-get upgrade -y && apt-get install -y libsecret-1-0 libsecret-1-dev + +WORKDIR /app +ENV PATH="/app/node_modules/.bin:${PATH}" + +COPY ./ ./ + +RUN rm -rf node_modules && APP_ENV=web yarn && SDK_API_URL='https://api.lbry.tv/api/proxy' NODE_ENV=production yarn compile:web --display errors-only +CMD node ./dist/web/server.js \ No newline at end of file diff --git a/flow-typed/npm/react-pose_vx.x.x.js b/flow-typed/npm/react-pose_vx.x.x.js deleted file mode 100644 index 43090a689..000000000 --- a/flow-typed/npm/react-pose_vx.x.x.js +++ /dev/null @@ -1,60 +0,0 @@ -// flow-typed signature: dbdb6148e2902ceaf3e437a7fe96ffa1 -// flow-typed version: <>/react-pose_v^4.0.5/flow_v0.94.0 - -/** - * This is an autogenerated libdef stub for: - * - * 'react-pose' - * - * Fill this stub out by replacing all the `any` types. - * - * Once filled out, we encourage you to share your work with the - * community by sending a pull request to: - * https://github.com/flowtype/flow-typed - */ - -declare module 'react-pose' { - declare module.exports: any; -} - -/** - * We include stubs for each file inside this npm package in case you need to - * require those files directly. Feel free to delete any files that aren't - * needed. - */ -declare module 'react-pose/dist/react-pose.dev' { - declare module.exports: any; -} - -declare module 'react-pose/dist/react-pose.es' { - declare module.exports: any; -} - -declare module 'react-pose/dist/react-pose' { - declare module.exports: any; -} - -declare module 'react-pose/lib/index' { - declare module.exports: any; -} - -declare module 'react-pose/rollup.config' { - declare module.exports: any; -} - -// Filename aliases -declare module 'react-pose/dist/react-pose.dev.js' { - declare module.exports: $Exports<'react-pose/dist/react-pose.dev'>; -} -declare module 'react-pose/dist/react-pose.es.js' { - declare module.exports: $Exports<'react-pose/dist/react-pose.es'>; -} -declare module 'react-pose/dist/react-pose.js' { - declare module.exports: $Exports<'react-pose/dist/react-pose'>; -} -declare module 'react-pose/lib/index.js' { - declare module.exports: $Exports<'react-pose/lib/index'>; -} -declare module 'react-pose/rollup.config.js' { - declare module.exports: $Exports<'react-pose/rollup.config'>; -} diff --git a/flow-typed/user.js b/flow-typed/user.js deleted file mode 100644 index 6ac74d620..000000000 --- a/flow-typed/user.js +++ /dev/null @@ -1,24 +0,0 @@ -// @flow - -// Move this to lbryinc -declare type User = { - created_at: string, - family_name: ?string, - given_name: ?string, - groups: Array, - has_verified_email: boolean, - id: number, - invite_reward_claimed: boolean, - invited_at: ?number, - invited_by_id: number, - invites_remaining: number, - is_email_enabled: boolean, - is_identity_verified: boolean, - is_reward_approved: boolean, - language: string, - manual_approval_user_id: ?number, - primary_email: string, - reward_status_change_trigger: string, - updated_at: string, - youtube_channels: ?Array, -}; diff --git a/package.json b/package.json index 3fdf2ca0e..f21d13405 100644 --- a/package.json +++ b/package.json @@ -128,8 +128,8 @@ "husky": "^0.14.3", "json-loader": "^0.5.4", "lbry-format": "https://github.com/lbryio/lbry-format.git", - "lbry-redux": "lbryio/lbry-redux#64383d57873ce59dea9df7216ee6cf52c4e95dc6", - "lbryinc": "lbryio/lbryinc#d250096a6fc5df16be4f82812ecce28d6e558b6e", + "lbry-redux": "lbryio/lbry-redux#42bf926138872d14523be7191694309be4f37605", + "lbryinc": "lbryio/lbryinc#67bb3e215be3f13605c5e3f9f2b0e2fb880724cf", "lint-staged": "^7.0.2", "localforage": "^1.7.1", "lodash-es": "^4.17.14", @@ -157,7 +157,6 @@ "react-hot-loader": "^4.11.1", "react-modal": "^3.1.7", "react-paginate": "^5.2.1", - "react-pose": "^4.0.5", "react-redux": "^6.0.1", "react-router": "^5.0.0", "react-router-dom": "^5.0.0", diff --git a/src/platforms/electron/createWindow.js b/src/platforms/electron/createWindow.js index a51930dfd..0b0be66c1 100644 --- a/src/platforms/electron/createWindow.js +++ b/src/platforms/electron/createWindow.js @@ -17,7 +17,7 @@ export default appState => { }); const windowConfiguration = { - backgroundColor: '#270f34', // Located in src/scss/init/_vars.scss `--color-background` + backgroundColor: '#270f34', // Located in src/scss/init/_vars.scss `--color-background--splash` minWidth: 950, minHeight: 600, autoHideMenuBar: true, diff --git a/src/platforms/electron/index.js b/src/platforms/electron/index.js index 5eff94534..de5278048 100644 --- a/src/platforms/electron/index.js +++ b/src/platforms/electron/index.js @@ -31,8 +31,7 @@ let showingAutoUpdateCloseAlert = false; // object is garbage collected. let rendererWindow; -// eslint-disable-next-line no-unused-vars -let tray; +let tray; // eslint-disable-line let daemon; const appState = {}; @@ -47,7 +46,6 @@ if (isDev) { process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true; } -// eslint-disable-next-line space-before-function-paren const startDaemon = async () => { let isDaemonRunning = false; @@ -114,7 +112,6 @@ if (!gotSingleInstanceLock) { } }); - // eslint-disable-next-line space-before-function-paren app.on('ready', async () => { await startDaemon(); startSandbox(); @@ -317,6 +314,12 @@ ipcMain.on('set-auth-token', (event, token) => { keytar.setPassword('LBRY', 'auth_token', token ? token.toString().trim() : null); }); +ipcMain.on('delete-auth-token', (event, password) => { + keytar.deletePassword('LBRY', 'auth_token', password).then(res => { + event.sender.send('delete-auth-token-response', res); + }); +}); + ipcMain.on('get-password', event => { keytar.getPassword('LBRY', 'wallet_password').then(password => { event.sender.send('get-password-response', password ? password.toString() : null); diff --git a/src/platforms/web/server.js b/src/platforms/web/server.js index e9f145509..3494190ac 100644 --- a/src/platforms/web/server.js +++ b/src/platforms/web/server.js @@ -1,8 +1,5 @@ const { parseURI } = require('lbry-redux'); // const { generateStreamUrl } = require('../../src/ui/util/lbrytv'); -function generateStreamUrl(claimName, claimId) { - return `https://api.lbry.tv/content/claims/${claimName}/${claimId}/stream`; -} const { WEB_SERVER_PORT } = require('../../config'); const { readFileSync } = require('fs'); const express = require('express'); @@ -72,7 +69,7 @@ app.get('*', async (req, res) => { let html = readFileSync(path.join(__dirname, '/index.html'), 'utf8'); const urlPath = req.path.substr(1); // trim leading slash - if (urlPath.match(/^([^@/:]+)\/([^:/]+)$/)) { + if (!urlPath.startsWith('$/') && urlPath.match(/^([^@/:]+)\/([^:/]+)$/)) { return res.redirect(301, req.url.replace(/([^/:]+)\/([^:/]+)/, '$1:$2')); // test against urlPath, but use req.url to retain parameters } diff --git a/src/ui/component/app/index.js b/src/ui/component/app/index.js index 6360fa5f2..ec011bb9e 100644 --- a/src/ui/component/app/index.js +++ b/src/ui/component/app/index.js @@ -1,11 +1,11 @@ +import * as SETTINGS from 'constants/settings'; import { hot } from 'react-hot-loader/root'; import { connect } from 'react-redux'; -import { doFetchTransactions } from 'lbry-redux'; import { selectUser, doRewardList, doFetchRewardedContent, doFetchAccessToken, selectAccessToken } from 'lbryinc'; +import { doFetchTransactions, doFetchChannelListMine } from 'lbry-redux'; import { makeSelectClientSetting, selectThemePath } from 'redux/selectors/settings'; import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded } from 'redux/selectors/app'; -import { doDownloadUpgradeRequested } from 'redux/actions/app'; -import * as SETTINGS from 'constants/settings'; +import { doDownloadUpgradeRequested, doSignIn } from 'redux/actions/app'; import App from './view'; const select = state => ({ @@ -23,6 +23,8 @@ const perform = dispatch => ({ fetchTransactions: () => dispatch(doFetchTransactions()), fetchAccessToken: () => dispatch(doFetchAccessToken()), requestDownloadUpgrade: () => dispatch(doDownloadUpgradeRequested()), + fetchChannelListMine: () => dispatch(doFetchChannelListMine()), + onSignedIn: () => dispatch(doSignIn()), }); export default hot( diff --git a/src/ui/component/app/view.jsx b/src/ui/component/app/view.jsx index df050ba9a..f17ee1a66 100644 --- a/src/ui/component/app/view.jsx +++ b/src/ui/component/app/view.jsx @@ -2,7 +2,7 @@ import * as ICONS from 'constants/icons'; import React, { useEffect, useRef } from 'react'; import analytics from 'analytics'; -import { Lbry, buildURI, parseURI } from 'lbry-redux'; +import { buildURI, parseURI } from 'lbry-redux'; import Router from 'component/router/index'; import ModalRouter from 'modal/modalRouter'; import ReactModal from 'react-modal'; @@ -12,6 +12,7 @@ import Yrbl from 'component/yrbl'; import FileViewer from 'component/fileViewer'; import { withRouter } from 'react-router'; import usePrevious from 'util/use-previous'; +import Button from 'component/button'; export const MAIN_WRAPPER_CLASS = 'main-wrapper'; @@ -20,7 +21,6 @@ type Props = { pageTitle: ?string, language: string, theme: string, - accessToken: ?string, user: ?{ id: string, has_verified_email: boolean, is_reward_approved: boolean }, location: { pathname: string, hash: string }, fetchRewards: () => void, @@ -30,6 +30,8 @@ type Props = { autoUpdateDownloaded: boolean, isUpgradeAvailable: boolean, requestDownloadUpgrade: () => void, + fetchChannelListMine: () => void, + onSignedIn: () => void, }; function App(props: Props) { @@ -40,10 +42,11 @@ function App(props: Props) { fetchTransactions, user, fetchAccessToken, - accessToken, requestDownloadUpgrade, autoUpdateDownloaded, isUpgradeAvailable, + fetchChannelListMine, + onSignedIn, } = props; const appRef = useRef(); const isEnhancedLayout = useKonamiListener(); @@ -70,8 +73,9 @@ function App(props: Props) { // @if TARGET='app' fetchRewards(); fetchTransactions(); + fetchChannelListMine(); // This needs to be done for web too... // @endif - }, [fetchRewards, fetchRewardedContent, fetchTransactions, fetchAccessToken]); + }, [fetchRewards, fetchRewardedContent, fetchTransactions, fetchAccessToken, fetchChannelListMine]); useEffect(() => { // $FlowFixMe @@ -87,24 +91,27 @@ function App(props: Props) { useEffect(() => { // Check that previousHasVerifiedEmail was not undefined instead of just not truthy // This ensures we don't fire the emailVerified event on the initial user fetch - if (previousHasVerifiedEmail !== undefined && hasVerifiedEmail) { + if (previousHasVerifiedEmail === false && hasVerifiedEmail) { analytics.emailVerifiedEvent(); } - }, [previousHasVerifiedEmail, hasVerifiedEmail]); + }, [previousHasVerifiedEmail, hasVerifiedEmail, onSignedIn]); useEffect(() => { - if (previousRewardApproved !== undefined && isRewardApproved) { + if (previousRewardApproved === false && isRewardApproved) { analytics.rewardEligibleEvent(); } }, [previousRewardApproved, isRewardApproved]); - // @if TARGET='web' + // Keep this at the end to ensure initial setup effects are run first useEffect(() => { - if (hasVerifiedEmail && accessToken) { - Lbry.setApiHeader('X-Lbry-Auth-Token', accessToken); + if (!previousHasVerifiedEmail && hasVerifiedEmail) { + onSignedIn(); } - }, [hasVerifiedEmail, accessToken]); - // @endif + }, [previousHasVerifiedEmail, hasVerifiedEmail, onSignedIn]); + + if (!user) { + return null; + } return (
openContextMenu(e)}> diff --git a/src/ui/component/cardVerify/view.jsx b/src/ui/component/cardVerify/view.jsx index 5531a1283..744cf02cb 100644 --- a/src/ui/component/cardVerify/view.jsx +++ b/src/ui/component/cardVerify/view.jsx @@ -1,4 +1,5 @@ -// @flow +/* eslint-disable no-undef */ +/* eslint-disable react/prop-types */ import React from 'react'; import Button from 'component/button'; @@ -6,35 +7,33 @@ let scriptLoading = false; let scriptLoaded = false; let scriptDidError = false; -type Props = { - disabled: boolean, - label: ?string, - email: string, +// Flow does not like the way this stripe plugin works +// Disabled because it was a huge pain +// type Props = { +// disabled: boolean, +// label: ?string, +// email: string, - // ===================================================== - // Required by stripe - // see Stripe docs for more info: - // https://stripe.com/docs/checkout#integration-custom - // ===================================================== +// // ===================================================== +// // Required by stripe +// // see Stripe docs for more info: +// // https://stripe.com/docs/checkout#integration-custom +// // ===================================================== - // Your publishable key (test or live). - // can't use "key" as a prop in react, so have to change the keyname - stripeKey: string, +// // Your publishable key (test or live). +// // can't use "key" as a prop in react, so have to change the keyname +// stripeKey: string, - // The callback to invoke when the Checkout process is complete. - // function(token) - // token is the token object created. - // token.id can be used to create a charge or customer. - // token.email contains the email address entered by the user. - token: string, -}; +// // The callback to invoke when the Checkout process is complete. +// // function(token) +// // token is the token object created. +// // token.id can be used to create a charge or customer. +// // token.email contains the email address entered by the user. +// token: string, +// }; -type State = { - open: boolean, -}; - -class CardVerify extends React.Component { - constructor(props: Props) { +class CardVerify extends React.Component { + constructor(props) { super(props); this.state = { open: false, @@ -87,6 +86,7 @@ class CardVerify extends React.Component { this.loadPromise.promise.then(this.onScriptLoaded).catch(this.onScriptError); + // $FlowFixMe document.body.appendChild(script); } @@ -161,7 +161,7 @@ class CardVerify extends React.Component { render() { return (
)} - {injectedItem &&
{injectedItem}
} - {urisLength > 0 && (
    {sortedUris.map((uri, index) => ( @@ -121,6 +117,7 @@ export default function ClaimList(props: Props) { ))}
)} + {urisLength === 0 && !loading &&

{empty || __('No results')}

} ); diff --git a/src/ui/component/claimListDiscover/view.jsx b/src/ui/component/claimListDiscover/view.jsx index 20f5548e7..5dc75acf9 100644 --- a/src/ui/component/claimListDiscover/view.jsx +++ b/src/ui/component/claimListDiscover/view.jsx @@ -32,13 +32,13 @@ type Props = { uris: Array, subscribedChannels: Array, doClaimSearch: ({}) => void, - injectedItem: any, tags: Array, loading: boolean, personalView: boolean, doToggleTagFollow: string => void, meta?: Node, showNsfw: boolean, + hideCustomization: boolean, history: { action: string, push: string => void, replace: string => void }, location: { search: string, pathname: string }, claimSearchByQuery: { @@ -54,21 +54,21 @@ function ClaimListDiscover(props: Props) { tags, loading, personalView, - injectedItem, meta, subscribedChannels, showNsfw, history, location, hiddenUris, + hideCustomization, } = props; const didNavigateForward = history.action === 'PUSH'; + const [page, setPage] = useState(1); const { search } = location; const urlParams = new URLSearchParams(search); - const personalSort = urlParams.get('sort') || SEARCH_SORT_YOU; + const personalSort = urlParams.get('sort') || (hideCustomization ? SEARCH_SORT_ALL : SEARCH_SORT_YOU); const typeSort = urlParams.get('type') || TYPE_TRENDING; const timeSort = urlParams.get('time') || TIME_WEEK; - const [page, setPage] = useState(1); const tagsInUrl = urlParams.get('t') || ''; const options: { page_size: number, @@ -86,7 +86,7 @@ function ClaimListDiscover(props: Props) { // no_totals makes it so the sdk doesn't have to calculate total number pages for pagination // it's faster, but we will need to remove it if we start using total_pages no_totals: true, - any_tags: (personalView && personalSort === SEARCH_SORT_YOU) || !personalView ? tags : [], + any_tags: (personalView && !hideCustomization && personalSort === SEARCH_SORT_YOU) || !personalView ? tags : [], channel_ids: personalSort === SEARCH_SORT_CHANNELS ? subscribedChannels.map(sub => sub.uri.split('#')[1]) : [], not_channel_ids: hiddenUris && hiddenUris.length ? hiddenUris.map(hiddenUri => hiddenUri.split('#')[1]) : [], not_tags: !showNsfw ? MATURE_TAGS : [], @@ -191,29 +191,33 @@ function ClaimListDiscover(props: Props) { ))} - {__('For')} - {!personalView && tags && tags.length ? ( - tags.map(tag => ) - ) : ( - { - handlePersonalSort(e.target.value); - }} - > - {SEARCH_FILTER_TYPES.map(type => ( - - ))} - + {!hideCustomization && ( + + {__('For')} + {!personalView && tags && tags.length ? ( + tags.map(tag => ) + ) : ( + { + handlePersonalSort(e.target.value); + }} + > + {SEARCH_FILTER_TYPES.map(type => ( + + ))} + + )} + )} {typeSort === 'top' && ( +
+
+ {icon && } +
+

{title}

+

{subtitle}

+
+
+
+ + {body &&
{body}
} + {actions && ( +
{actions}
+ )} + + ); +} diff --git a/src/ui/component/common/form-components/form-field.jsx b/src/ui/component/common/form-components/form-field.jsx index 23f4870f8..adead91ca 100644 --- a/src/ui/component/common/form-components/form-field.jsx +++ b/src/ui/component/common/form-components/form-field.jsx @@ -162,11 +162,7 @@ export class FormField extends React.PureComponent { - {prefix && ( - - )} + {prefix && } {inner} diff --git a/src/ui/component/common/form-components/form.jsx b/src/ui/component/common/form-components/form.jsx index 95197d96b..a9d67436c 100644 --- a/src/ui/component/common/form-components/form.jsx +++ b/src/ui/component/common/form-components/form.jsx @@ -11,6 +11,7 @@ export class Form extends React.PureComponent { const { children, onSubmit, ...otherProps } = this.props; return (
{ event.preventDefault(); diff --git a/src/ui/component/common/icon-custom.jsx b/src/ui/component/common/icon-custom.jsx index e98bce146..857153c2c 100644 --- a/src/ui/component/common/icon-custom.jsx +++ b/src/ui/component/common/icon-custom.jsx @@ -302,4 +302,9 @@ export const icons = { ), + [ICONS.PHONE]: buildIcon( + + + + ), }; diff --git a/src/ui/component/common/icon.jsx b/src/ui/component/common/icon.jsx index 75e66b091..4951f050c 100644 --- a/src/ui/component/common/icon.jsx +++ b/src/ui/component/common/icon.jsx @@ -17,6 +17,7 @@ type Props = { iconColor?: string, size?: number, className?: string, + sectionIcon?: boolean, }; class IconComponent extends React.PureComponent { @@ -49,11 +50,10 @@ class IconComponent extends React.PureComponent { }; render() { - const { icon, tooltip, iconColor, size, className } = this.props; + const { icon, tooltip, iconColor, size, className, sectionIcon = false } = this.props; const Icon = icons[this.props.icon]; if (!Icon) { - console.error('no icon found for ', icon); return null; } @@ -69,7 +69,11 @@ class IconComponent extends React.PureComponent { tooltipText = this.getTooltip(icon); } - const inner = ; + const component = ( + + ); + + const inner = sectionIcon ? {component} : component; return tooltipText ? {inner} : inner; } diff --git a/src/ui/component/header/index.js b/src/ui/component/header/index.js index 172ad6e3e..e253781c3 100644 --- a/src/ui/component/header/index.js +++ b/src/ui/component/header/index.js @@ -1,9 +1,10 @@ import * as SETTINGS from 'constants/settings'; import { connect } from 'react-redux'; import { selectBalance, formatCredits } from 'lbry-redux'; -import { selectUserEmail } from 'lbryinc'; +import { selectUserVerifiedEmail } from 'lbryinc'; import { doSetClientSetting } from 'redux/actions/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings'; +import { doSignOut } from 'redux/actions/app'; import Header from './view'; const select = state => ({ @@ -13,11 +14,12 @@ const select = state => ({ currentTheme: makeSelectClientSetting(SETTINGS.THEME)(state), automaticDarkModeEnabled: makeSelectClientSetting(SETTINGS.AUTOMATIC_DARK_MODE_ENABLED)(state), hideBalance: makeSelectClientSetting(SETTINGS.HIDE_BALANCE)(state), - email: selectUserEmail(state), + email: selectUserVerifiedEmail(state), }); const perform = dispatch => ({ setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)), + signOut: () => dispatch(doSignOut()), }); export default connect( diff --git a/src/ui/component/header/view.jsx b/src/ui/component/header/view.jsx index 9461cd864..dacdf3275 100644 --- a/src/ui/component/header/view.jsx +++ b/src/ui/component/header/view.jsx @@ -12,22 +12,6 @@ import Icon from 'component/common/icon'; import { Menu, MenuList, MenuButton, MenuItem } from '@reach/menu-button'; import Tooltip from 'component/common/tooltip'; -// Move this into jessops password util -import cookie from 'cookie'; -// @if TARGET='app' -import keytar from 'keytar'; -// @endif; -function deleteAuthToken() { - // @if TARGET='app' - keytar.deletePassword('LBRY', 'auth_token').catch(console.error); //eslint-disable-line - // @endif; - // @if TARGET='web' - document.cookie = cookie.serialize('auth_token', '', { - expires: new Date(), - }); - // @endif -} - type Props = { autoUpdateDownloaded: boolean, balance: string, @@ -41,6 +25,7 @@ type Props = { hideBalance: boolean, email: ?string, minimal: boolean, + signOut: () => void, }; const Header = (props: Props) => { @@ -53,11 +38,9 @@ const Header = (props: Props) => { hideBalance, email, minimal, + signOut, } = props; - const showUpgradeButton = autoUpdateDownloaded || (process.platform === 'linux' && isUpgradeAvailable); - const isAuthenticated = Boolean(email); - // Auth is optional in the desktop app - const showFullHeader = IS_WEB ? isAuthenticated : true; + const authenticated = Boolean(email); function handleThemeToggle() { if (automaticDarkModeEnabled) { @@ -71,42 +54,14 @@ const Header = (props: Props) => { } } - function signOut() { - // Replace this with actual clearUser function - window.store.dispatch({ type: 'USER_FETCH_FAILURE' }); - deleteAuthToken(); - location.reload(); - } - - const accountMenuButtons = [ - { - path: `/$/account`, - icon: ICONS.OVERVIEW, - label: __('Overview'), - }, - { - path: `/$/rewards`, - icon: ICONS.FEATURED, - label: __('Rewards'), - }, - { - path: `/$/wallet`, - icon: ICONS.WALLET, - label: __('Wallet'), - }, - { - path: `/$/publish`, - icon: ICONS.PUBLISH, - label: __('Publish'), - }, - ]; - - if (!isAuthenticated) { - accountMenuButtons.push({ - onClick: signOut, - icon: ICONS.PUBLISH, - label: __('Publish'), - }); + function getWalletTitle() { + return hideBalance ? ( + __('Wallet') + ) : ( + + {roundedBalance} + + ); } return ( @@ -146,19 +101,17 @@ const Header = (props: Props) => { {!minimal ? ( -
- {showFullHeader ? ( +
+ {!IS_WEB || authenticated ? ( - - {roundedBalance} - + {getWalletTitle()} - history.push(`/$/wallet`)}> + history.push(`/$/${PAGES.WALLET}`)}> {__('Wallet')} - history.push(`/$/rewards`)}> + history.push(`/$/${PAGES.REWARDS}`)}> {__('Rewards')} @@ -169,19 +122,16 @@ const Header = (props: Props) => { - history.push(isAuthenticated ? `/$/account` : `/$/auth/signup`)} - > + history.push(`/$/${PAGES.ACCOUNT}`)}> {__('Overview')} - history.push(`/$/publish`)}> + history.push(`/$/${PAGES.PUBLISH}`)}> {__('Publish')} - {isAuthenticated ? ( + {authenticated ? ( {__('Sign Out')} @@ -197,11 +147,11 @@ const Header = (props: Props) => { - history.push(`/$/settings`)}> + history.push(`/$/${PAGES.SETTINGS}`)}> {__('Settings')} - history.push(`/$/help`)}> + history.push(`/$/${PAGES.HELP}`)}> {__('Help')} @@ -213,10 +163,7 @@ const Header = (props: Props) => { ) : ( - - -
) : ( diff --git a/src/ui/component/inviteList/view.jsx b/src/ui/component/inviteList/view.jsx index b3a1146d6..61ab0a7ac 100644 --- a/src/ui/component/inviteList/view.jsx +++ b/src/ui/component/inviteList/view.jsx @@ -1,7 +1,6 @@ // @flow import React from 'react'; import RewardLink from 'component/rewardLink'; -import Yrbl from 'component/yrbl'; import { rewards } from 'lbryinc'; import Icon from 'component/common/icon'; import * as ICONS from 'constants/icons'; @@ -20,22 +19,10 @@ class InviteList extends React.PureComponent { render() { const { invitees, referralReward } = this.props; - if (!invitees) { + if (!invitees || !invitees.length) { return null; } - if (!invitees.length) { - return ( - - ); - } - let rewardAmount = 0; let rewardHelp = __( "Woah, you have a lot of friends! You've claimed the maximum amount of referral rewards. Check back soon to see if more are available!." @@ -60,10 +47,10 @@ class InviteList extends React.PureComponent { /> )} -

{rewardHelp}

+

{rewardHelp}

- +
diff --git a/src/ui/component/inviteNew/view.jsx b/src/ui/component/inviteNew/view.jsx index f9417c279..93a677168 100644 --- a/src/ui/component/inviteNew/view.jsx +++ b/src/ui/component/inviteNew/view.jsx @@ -3,6 +3,7 @@ import React from 'react'; import Button from 'component/button'; import { Form, FormField } from 'component/common/form'; import CopyableText from 'component/copyableText'; +import Card from 'component/common/card'; type FormProps = { inviteNew: string => void, @@ -73,25 +74,28 @@ class InviteNew extends React.PureComponent { const { errorMessage, inviteNew, isPending, rewardAmount, referralLink } = this.props; return ( -
-

{__('Invite a Friend')}

-

{__('When your friends start using LBRY, the network gets stronger!')}

+ + + - - - -

- {__('Earn')}

+

+ {__('Earn')}

{__('Invitee Email')}